using Nop.Core;
using Nop.Core.Caching;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Directory;
using Nop.Core.Domain.Discounts;
using Nop.Core.Domain.Forums;
using Nop.Core.Domain.Localization;
using Nop.Core.Domain.Logistics;
using Nop.Core.Domain.Media;
using Nop.Core.Domain.Messages;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Payments;
using Nop.Core.Domain.Shipping;
using Nop.Core.Domain.Stores;
using Nop.Core.Domain.Tax;
using Nop.Services.Authentication;
using Nop.Services.Authentication.External;
using Nop.Services.Catalog;
using Nop.Services.Common;
using Nop.Services.Customers;
using Nop.Services.Directory;
using Nop.Services.Helpers;
using Nop.Services.Localization;
using Nop.Services.Logging;
using Nop.Services.Logistics;
using Nop.Services.Media;
using Nop.Services.Messages;
using Nop.Services.Orders;
using Nop.Services.Payments;
using Nop.Services.Security;
using Nop.Services.Seo;
using Nop.Services.Shipping;
using Nop.Services.Stores;
using Nop.Services.Tax;
using Nop.Web.Framework;
using Nop.Web.Framework.Controllers;
using Nop.Web.Framework.Security;
using Nop.Web.Framework.UI;
using Nop.Web.Framework.UI.Captcha;
using Nop.Web.Infrastructure.Cache;
using Nop.Web.Models.Checkout;
using Nop.Web.Models.Common;
using SpotsHub.Gateway.Extensions;
using SpotsHub.Gateway.Models.Common;
using SpotsHub.Gateway.Models.Customer;
using SpotsHub.Gateway.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Telerik.Web.Mvc;

namespace SpotsHub.Gateway.Controllers
{
    public class CustomerController : BaseController
    {
        #region Fields

        private readonly IAuthenticationService _authenticationService;
        private readonly IDateTimeHelper _dateTimeHelper;
        private readonly DateTimeSettings _dateTimeSettings;
        private readonly ILocalizationService _localizationService;
        private readonly IPaymentService _paymentService;
        private readonly IWorkContext _workContext;
        private readonly ICustomerService _customerService;
        private readonly IGenericAttributeService _genericAttributeService;
        private readonly ICustomerRegistrationService _customerRegistrationService;
        private readonly ForumSettings _forumSettings;
        private readonly RewardPointsSettings _rewardPointsSettings;
        private readonly CustomerSettings _customerSettings;
        private readonly AddressSettings _addressSettings;
        private readonly OrderSettings _orderSettings;
        private readonly MediaSettings _mediaSettings;
        private readonly MeasureSettings _measureSettings;
        private readonly TaxSettings _taxSettings;
        private readonly ITaxService _taxService;
        private readonly IOpenAuthenticationService _openAuthenticationService;
        private readonly IAddressService _addressService;
        private readonly ICountryService _countryService;
        private readonly IStateProvinceService _stateProvinceService;
        private readonly IOrderTotalCalculationService _orderTotalCalculationService;
        private readonly Nop.Services.Orders.IOrderProcessingService _orderProcessingService;
        private readonly Nop.Services.Logistics.IOrderProcessingService _logisticsOrderProcessingService;
        private readonly IPictureService _pictureService;
        private readonly ILogisticsService _logisticsService;
        private readonly IOrderService _orderService;
        private readonly ICurrencyService _currencyService;
        private readonly INewsLetterSubscriptionService _newsLetterSubscriptionService;
        private readonly IShoppingCartService _shoppingCartService;
        private readonly IProductService _productService;
        private readonly IWebHelper _webHelper;
        private readonly IPriceFormatter _priceFormatter;
        private readonly ICustomerActivityService _customerActivityService;
        private readonly IPermissionService _permissionService;
        private readonly IBackInStockSubscriptionService _backInStockSubscriptionService;
        private readonly IWorkflowMessageService _workflowMessageService;
        private readonly IMeasureService _measureService;
        private readonly LocalizationSettings _localizationSettings;
        private readonly CaptchaSettings _captchaSettings;
        private readonly ExternalAuthenticationSettings _externalAuthenticationSettings;
        private readonly ICacheManager _cacheManager;
        private readonly LogisticsInformationSettings _logisticsInformationSettings;
        private readonly IDownloadService _downloadService;
        private readonly IInvoiceService _invoiceService;
        private readonly HttpContextBase _httpContext;
        private readonly IPdfService _pdfService;
        private readonly IShipmentService _shipmentService;
        private readonly ILogisticsProcessingService _logisticsProcessingService;
        private readonly IRegionService _regionService;
        private readonly ILanguageService _languageService;
        private readonly PaymentSettings _paymentSettings;
        private readonly CurrencySettings _currencySettings;
        private readonly Nop.Services.Configuration.ISettingService _settingService;

        private readonly Nop.Services.Logistics.IOrderProcessingService _orderlogisticsProcessingService;

        #endregion

        #region Ctor

        public CustomerController(IAuthenticationService authenticationService,
            IDateTimeHelper dateTimeHelper, TaxSettings taxSettings,
            DateTimeSettings dateTimeSettings, MediaSettings mediaSettings,
            ILocalizationService localizationService, IOpenAuthenticationService openAuthenticationService,
            IPaymentService paymentService, IPriceFormatter priceFormatter,
            IWorkContext workContext, ICustomerService customerService,
            IGenericAttributeService genericAttributeService, ILanguageService languageService,
            ICustomerRegistrationService customerRegistrationService,
            ITaxService taxService, RewardPointsSettings rewardPointsSettings, MeasureSettings measureSettings,
            CustomerSettings customerSettings, AddressSettings addressSettings, ForumSettings forumSettings,
            OrderSettings orderSettings, IAddressService addressService,
            ICountryService countryService, IStateProvinceService stateProvinceService,
            IOrderTotalCalculationService orderTotalCalculationService,
            Nop.Services.Logistics.IOrderProcessingService logisticsOrderProcessingService,
            Nop.Services.Orders.IOrderProcessingService orderProcessingService, IOrderService orderService,
            ICurrencyService currencyService, ILogisticsService logisticsService,
            INewsLetterSubscriptionService newsLetterSubscriptionService, IMeasureService measureService,
            IBackInStockSubscriptionService backInStockSubscriptionService,
            IShoppingCartService shoppingCartService, IProductService productService,
            IPermissionService permissionService, IInvoiceService invoiceService,
            IWebHelper webHelper, IDownloadService downloadService, IPictureService pictureService,
            ICustomerActivityService customerActivityService, ICacheManager cacheManager,
            IWorkflowMessageService workflowMessageService, LocalizationSettings localizationSettings,
            CaptchaSettings captchaSettings, ExternalAuthenticationSettings externalAuthenticationSettings,
            LogisticsInformationSettings logisticsInformationSettings,
            HttpContextBase httpContext, IPdfService pdfService, IRegionService regionService,
            IShipmentService shipmentService, ILogisticsProcessingService logisticsProcessingService,
            PaymentSettings paymentSettings, CurrencySettings currencySettings,
            Nop.Services.Logistics.IOrderProcessingService orderlogisticsProcessingService,
            Nop.Services.Configuration.ISettingService settingService)
        {
            this._authenticationService = authenticationService;
            this._dateTimeHelper = dateTimeHelper;
            this._dateTimeSettings = dateTimeSettings;
            this._localizationService = localizationService;
            this._paymentService = paymentService;
            this._workContext = workContext;
            this._customerService = customerService;
            this._genericAttributeService = genericAttributeService;
            this._customerRegistrationService = customerRegistrationService;
            this._rewardPointsSettings = rewardPointsSettings;
            this._customerSettings = customerSettings;
            this._addressSettings = addressSettings;
            this._addressService = addressService;
            this._countryService = countryService;
            this._forumSettings = forumSettings;
            this._orderSettings = orderSettings;
            this._mediaSettings = mediaSettings;
            this._taxSettings = taxSettings;
            this._taxService = taxService;
            this._stateProvinceService = stateProvinceService;
            this._orderProcessingService = orderProcessingService;
            this._logisticsOrderProcessingService = logisticsOrderProcessingService;
            this._orderTotalCalculationService = orderTotalCalculationService;
            this._orderService = orderService;
            this._languageService = languageService;
            this._priceFormatter = priceFormatter;
            this._currencyService = currencyService;
            this._newsLetterSubscriptionService = newsLetterSubscriptionService;
            this._backInStockSubscriptionService = backInStockSubscriptionService;
            this._shoppingCartService = shoppingCartService;
            this._pictureService = pictureService;
            this._productService = productService;
            this._permissionService = permissionService;
            this._invoiceService = invoiceService;
            this._logisticsService = logisticsService;
            this._openAuthenticationService = openAuthenticationService;
            this._webHelper = webHelper;
            this._customerActivityService = customerActivityService;
            this._cacheManager = cacheManager;
            this._httpContext = httpContext;
            this._regionService = regionService;
            this._downloadService = downloadService;
            this._workflowMessageService = workflowMessageService;
            this._localizationSettings = localizationSettings;
            this._captchaSettings = captchaSettings;
            this._measureService = measureService;
            this._measureSettings = measureSettings;
            this._externalAuthenticationSettings = externalAuthenticationSettings;
            this._logisticsInformationSettings = logisticsInformationSettings;
            this._pdfService = pdfService;
            this._permissionService = permissionService;
            this._shipmentService = shipmentService;
            this._logisticsProcessingService = logisticsProcessingService;
            this._httpContext = httpContext;
            this._orderlogisticsProcessingService = orderlogisticsProcessingService;
            this._currencySettings = currencySettings;
            this._paymentSettings = paymentSettings;
            this._settingService = settingService;
        }

        #endregion

        #region Methods

        #region Login

        [ChildActionOnly]
        public ActionResult LoginForm()
        {
            var model = new LoginModel();
            model.UsernamesEnabled = _customerSettings.UsernamesEnabled;
            model.DisplayCaptcha = _captchaSettings.Enabled && _captchaSettings.ShowOnLoginPage;
            return PartialView(model);
        }

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult Login(bool? checkoutAsGuest, bool checkout = false, bool directCheckout = false)
        {
            var model = new LoginModel();
            var customer = _workContext.CurrentCustomer;
            if (customer.IsRegistered())
            {
                model.Email = customer.Email;
                model.Username = _customerSettings.UsernamesEnabled ? customer.Username : "";
            }
            //else if (Request.Cookies["LastActive"] != null)
            //{
            //    model.Email = Request.Cookies["LastActive"].Value;
            //}
            model.IsCheckout = checkout || directCheckout;
            model.IsDirectCheckout = directCheckout;
            model.UsernamesEnabled = _customerSettings.UsernamesEnabled;
            model.DisplayCaptcha = _captchaSettings.Enabled && _captchaSettings.ShowOnLoginPage;
            return View(model);
        }

        [HttpPost]
        [CaptchaValidator]
        public ActionResult Login(LoginModel model, string returnUrl, bool captchaValid)
        {
            //validate CAPTCHA
            if (_captchaSettings.Enabled && _captchaSettings.ShowOnLoginPage && !captchaValid)
            {
                ModelState.AddModelError("", _localizationService.GetResource("Common.WrongCaptcha"));
            }

            if (ModelState.IsValid)
            {
                if (_customerSettings.UsernamesEnabled && model.Username != null)
                {
                    model.Username = model.Username.Trim();
                }

                if (_customerRegistrationService.ValidateCustomer(_customerSettings.UsernamesEnabled ? model.Username : model.Email, model.Password))
                {
                    var customer = _customerSettings.UsernamesEnabled ? _customerService.GetCustomerByUsername(model.Username) : _customerService.GetCustomerByEmail(model.Email);

                    //TODO: migrate shopping cart
                    //_shoppingCartService.MigrateShoppingCart(_workContext.CurrentCustomer, customer);

                    var origCustomer = _workContext.CurrentCustomer;

                    //sign in new customer
                    _authenticationService.SignIn(customer, model.RememberMe);

                    if (customer != null && origCustomer != null && origCustomer.ShoppingCartItems.Count > 0)
                    {
                        if (model.IsDirectCheckout)
                        {
                            foreach (var shoppingCartItem in customer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart).ToList())
                            {
                                _shoppingCartService.DeleteShoppingCartItem(shoppingCartItem);
                            }
                        }
                        _shoppingCartService.MigrateShoppingCart(origCustomer, customer);
                    }

                    //activity log
                    _customerActivityService.InsertActivity("Logistics.Login", _localizationService.GetResource("ActivityLog.PublicStore.Login"), customer);

                    //save as last active user
                    HttpCookie lastActive = new HttpCookie("LastActive");
                    lastActive.Expires = DateTime.UtcNow.AddMonths(3);
                    lastActive.Value = model.Email;
                    Response.Cookies.Add(lastActive);

                    if (!String.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
                        return Redirect(returnUrl);
                    else
                        return RedirectToRoute("HomePage");

                }
                else
                {
                    ModelState.AddModelError("", _localizationService.GetResource("Account.Login.WrongCredentials"));
                }
            }
            if (!ModelState.IsValid)
                ViewBag.Messages = RenderMessages();
            ModelState.Clear();
            //If we got this far, something failed, redisplay form
            model.UsernamesEnabled = _customerSettings.UsernamesEnabled;
            model.DisplayCaptcha = _captchaSettings.Enabled && _captchaSettings.ShowOnLoginPage;
            return View(model);
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult CheckUsernameAvailability(string username)
        {
            var usernameAvailable = false;
            var statusText = _localizationService.GetResource("Account.CheckUsernameAvailability.NotAvailable");

            if (_customerSettings.UsernamesEnabled && username != null)
            {
                username = username.Trim();

                if (UsernameIsValid(username))
                {
                    if (_workContext.CurrentCustomer != null &&
                        _workContext.CurrentCustomer.Username != null &&
                        _workContext.CurrentCustomer.Username.Equals(username, StringComparison.InvariantCultureIgnoreCase))
                    {
                        statusText = _localizationService.GetResource("Account.CheckUsernameAvailability.CurrentUsername");
                    }
                    else
                    {
                        var customer = _customerService.GetCustomerByUsername(username);
                        if (customer == null)
                        {
                            statusText = _localizationService.GetResource("Account.CheckUsernameAvailability.Available");
                            usernameAvailable = true;
                        }
                    }
                }
            }

            return Json(new { Available = usernameAvailable, Text = statusText });
        }

        [NonAction]
        protected bool UsernameIsValid(string username)
        {
            var result = true;

            if (String.IsNullOrEmpty(username))
            {
                return false;
            }

            // other validation 

            return result;
        }

        #endregion

        #region Register

        [NopHttpsRequirement(SslRequirement.Yes)]
        [MobileRedirect]
        public ActionResult Register()
        {
            try
            {
                //check whether registration is allowed
                if (_customerSettings.UserRegistrationType == UserRegistrationType.Disabled)
                    return RedirectToAction("RegisterResult", new { resultId = (int)UserRegistrationType.Disabled });

                var model = new LogisticsRegisterModel();
                PrepareRegisterModel(model);

                model.BillingAddress.AllowEmpty = true;

                return View(model);
            }
            catch (Exception)
            {
                return RedirectToRoute("HomePage");
            }
        }

        [HttpPost]
        [CaptchaValidator]
        [ValidateAntiForgeryToken]
        public ActionResult Register(LogisticsRegisterModel model, string returnUrl, bool captchaValid)
        {
            try
            {
                //check whether registration is allowed
                if (_customerSettings.UserRegistrationType == UserRegistrationType.Disabled)
                    return RedirectToAction("RegisterResult", new { resultId = (int)UserRegistrationType.Disabled });

                if (_workContext.CurrentCustomer.IsRegistered())
                {
                    //Already registered customer. 
                    _authenticationService.SignOut();

                    //Save a new record
                    _workContext.CurrentCustomer = _customerService.InsertGuestCustomer();
                }
                var customer = _workContext.CurrentCustomer;

                //validate CAPTCHA
                if (_captchaSettings.Enabled && _captchaSettings.ShowOnRegistrationPage && !captchaValid)
                {
                    ModelState.AddModelError("", _localizationService.GetResource("Common.WrongCaptcha"));
                }

                if (!model.Accepted)
                {
                    // +string+
                    ModelState.AddModelError("", "You must read and accept the condition first.");
                }

                //validate unique user
                if (_customerService.GetCustomerByEmail(model.RegisterModel.Email) != null)
                {
                    ModelState.AddModelError("", _localizationService.GetResource("Account.Register.Errors.EmailAlreadyExists"));
                }
                if (_customerSettings.UsernamesEnabled)
                {
                    if (_customerService.GetCustomerByUsername(model.RegisterModel.Username) != null)
                    {
                        ModelState.AddModelError("", _localizationService.GetResource("Account.Register.Errors.UsernameAlreadyExists"));
                    }
                }

                if (_customerSettings.DateOfBirthEnabled)
                {
                    if (!model.RegisterModel.DateOfBirthDay.HasValue || !(model.RegisterModel.DateOfBirthDay.Value > 0))
                    {
                        ModelState.AddModelError("RegisterModel.DateOfBirthDay", _localizationService.GetResource("Account.Register.Errors.DateOfBirthDayRequired"));
                    }
                    if (!model.RegisterModel.DateOfBirthMonth.HasValue || !(model.RegisterModel.DateOfBirthMonth.Value > 0))
                    {
                        ModelState.AddModelError("RegisterModel.DateOfBirthMonth", _localizationService.GetResource("Account.Register.Errors.DateOfBirthMonthRequired"));
                    }
                    if (!model.RegisterModel.DateOfBirthYear.HasValue || !(model.RegisterModel.DateOfBirthYear.Value > 0))
                    {
                        ModelState.AddModelError("RegisterModel.DateOfBirthYear", _localizationService.GetResource("Account.Register.Errors.DateOfBirthYearRequired"));
                    }
                }

                if (ModelState.IsValid)
                {
                    // Remove postal code spaces.

                    if (_customerSettings.UsernamesEnabled && model.RegisterModel.Username != null)
                    {
                        customer.Username = model.RegisterModel.Username.Trim();
                    }

                    var registrationRequest = new CustomerRegistrationRequest(customer, model.RegisterModel.Email,
                        _customerSettings.UsernamesEnabled ? model.RegisterModel.Username : model.RegisterModel.Email,
                        model.RegisterModel.Password, _customerSettings.DefaultPasswordFormat, true, _customerSettings.EnableFreeMembership);
                    var registrationResult = _customerRegistrationService.RegisterCustomer(registrationRequest);
                    if (registrationResult.Success)
                    {
                        //properties
                        //if (_dateTimeSettings.AllowCustomersToSetTimeZone)
                        //    customer.TimeZoneId = model.RegisterModel.TimeZoneId;
                        //save
                        //_customerService.UpdateCustomer(customer);

                        //form fields
                        if (_customerSettings.GenderEnabled)
                            _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Gender, model.RegisterModel.Gender);
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.FirstName, model.RegisterModel.FirstName);
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.LastName, model.RegisterModel.LastName);
                        if (_customerSettings.DateOfBirthEnabled)
                        {
                            DateTime? dateOfBirth = null;
                            try
                            {
                                dateOfBirth = new DateTime(model.RegisterModel.DateOfBirthYear.Value, model.RegisterModel.DateOfBirthMonth.Value, model.RegisterModel.DateOfBirthDay.Value);
                            }
                            catch { }
                            _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.DateOfBirth, dateOfBirth);
                        }
                        if (_customerSettings.CompanyEnabled)
                            _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Company, model.RegisterModel.Company);
                        if (_customerSettings.StreetAddressEnabled)
                            _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.StreetAddress, model.RegisterModel.StreetAddress);
                        if (_customerSettings.StreetAddress2Enabled)
                            _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.StreetAddress2, model.RegisterModel.StreetAddress2);
                        if (_customerSettings.ZipPostalCodeEnabled)
                        {
                            if (!string.IsNullOrEmpty(model.RegisterModel.ZipPostalCode))
                                model.RegisterModel.ZipPostalCode = model.RegisterModel.ZipPostalCode.Replace(" ", string.Empty).Trim().ToUpper();

                            _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.ZipPostalCode, model.RegisterModel.ZipPostalCode);
                        }
                        if (_customerSettings.CityEnabled)
                            _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.City, model.RegisterModel.City);
                        if (_customerSettings.CountryEnabled)
                            _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.CountryId, model.RegisterModel.CountryId);
                        if (_customerSettings.CountryEnabled && _customerSettings.StateProvinceEnabled)
                            _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.StateProvinceId, model.RegisterModel.StateProvinceId);
                        if (_customerSettings.PhoneEnabled)
                            _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Phone, model.RegisterModel.Phone);
                        if (_customerSettings.CellPhoneEnabled)
                            _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.CellPhone, model.RegisterModel.CellPhone);
                        if (_customerSettings.FaxEnabled)
                            _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Fax, model.RegisterModel.Fax);

                        //newsletter
                        if (_customerSettings.NewsletterEnabled)
                        {
                            //save newsletter value
                            var newsletter = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmail(model.RegisterModel.Email);
                            if (newsletter != null)
                            {
                                if (model.RegisterModel.Newsletter)
                                {
                                    newsletter.Active = true;
                                    _newsLetterSubscriptionService.UpdateNewsLetterSubscription(newsletter);
                                }
                                //else
                                //{
                                //When registering, not checking the newsletter check box should not take an existing email address off of the subscription list.
                                //_newsLetterSubscriptionService.DeleteNewsLetterSubscription(newsletter);
                                //}
                            }
                            else
                            {
                                if (model.RegisterModel.Newsletter)
                                {
                                    _newsLetterSubscriptionService.InsertNewsLetterSubscription(new NewsLetterSubscription()
                                    {
                                        NewsLetterSubscriptionGuid = Guid.NewGuid(),
                                        Email = model.RegisterModel.Email,
                                        Active = true,
                                        CreatedOnUtc = DateTime.UtcNow
                                    });
                                }
                            }
                        }

                        //TODO: associated with external account (if possible)
                        //TryAssociateAccountWithExternalAccount(customer);

                        //insert default address (if possible)
                        //var defaultAddress = new Address()
                        //{
                        //    FirstName = customer.GetAttribute<string>(SystemCustomerAttributeNames.FirstName),
                        //    LastName = customer.GetAttribute<string>(SystemCustomerAttributeNames.LastName),
                        //    Email = customer.Email,
                        //    Company = customer.GetAttribute<string>(SystemCustomerAttributeNames.Company),
                        //    CountryId = customer.GetAttribute<int>(SystemCustomerAttributeNames.CountryId) > 0 ?
                        //        (int?)customer.GetAttribute<int>(SystemCustomerAttributeNames.CountryId) : null,
                        //    StateProvinceId = customer.GetAttribute<int>(SystemCustomerAttributeNames.StateProvinceId) > 0 ?
                        //        (int?)customer.GetAttribute<int>(SystemCustomerAttributeNames.StateProvinceId) : null,
                        //    City = customer.GetAttribute<string>(SystemCustomerAttributeNames.City),
                        //    Address1 = customer.GetAttribute<string>(SystemCustomerAttributeNames.StreetAddress),
                        //    Address2 = customer.GetAttribute<string>(SystemCustomerAttributeNames.StreetAddress2),
                        //    ZipPostalCode = customer.GetAttribute<string>(SystemCustomerAttributeNames.ZipPostalCode),
                        //    PhoneNumber = customer.GetAttribute<string>(SystemCustomerAttributeNames.Phone),
                        //    CellPhoneNumber = customer.GetAttribute<string>(SystemCustomerAttributeNames.CellPhone),
                        //    FaxNumber = customer.GetAttribute<string>(SystemCustomerAttributeNames.Fax),
                        //    CreatedOnUtc = customer.CreatedOnUtc
                        //};
                        //Address billingAddress = null;
                        //if (!model.BillingAddress.AllowEmpty)
                        //{
                        //    billingAddress = new Address()
                        //    {
                        //        FirstName = model.BillingAddress.FirstName,
                        //        LastName = model.BillingAddress.LastName,
                        //        Email = model.BillingAddress.Email,
                        //        Company = model.BillingAddress.Company,
                        //        CountryId = model.BillingAddress.CountryId > 0 ? model.BillingAddress.CountryId : null,
                        //        StateProvinceId = model.BillingAddress.StateProvinceId > 0 ? model.BillingAddress.StateProvinceId : null,
                        //        City = model.BillingAddress.City,
                        //        Address1 = model.BillingAddress.Address1,
                        //        Address2 = model.BillingAddress.Address2,
                        //        ZipPostalCode = model.BillingAddress.ZipPostalCode,
                        //        PhoneNumber = model.BillingAddress.PhoneNumber,
                        //        CellPhoneNumber = model.BillingAddress.CellPhoneNumber,
                        //        FaxNumber = model.BillingAddress.FaxNumber,
                        //        CreatedOnUtc = customer.CreatedOnUtc
                        //    };
                        //}

                        //if (!_addressService.IsAddressValid(defaultAddress))
                        //{
                        //    ModelState.AddModelError("", "The permanent account address is not valid.");
                        //}
                        //else if (billingAddress != null && !_addressService.IsAddressValid(billingAddress))
                        //{
                        //    ModelState.AddModelError("", "The billing address is not valid.");
                        //}
                        //else
                        //{
                        ////some validation
                        //if (defaultAddress.CountryId == 0)
                        //    defaultAddress.CountryId = null;
                        //if (defaultAddress.StateProvinceId == 0)
                        //    defaultAddress.StateProvinceId = null;
                        ////set default address
                        //customer.Addresses.Add(defaultAddress);
                        //customer.BillingAddress = billingAddress ?? defaultAddress;
                        //if (billingAddress != null)
                        //{
                        //    customer.Addresses.Add(customer.BillingAddress);
                        //}
                        //customer.ShippingAddress = defaultAddress;
                        //var region = AddressHelper.GetRegionByPostalCode(defaultAddress.ZipPostalCode);

                        //if (region != null)
                        //{
                        //    customer.Region = region;
                        //}

                        //customer.TimeZoneId = AddressHelper.GetTimeZoneIdByRegion(region);
                        //_customerService.UpdateCustomer(customer);

                        customer.TimeZoneId = "Pacific Standard Time";

                        if (_customerSettings.UserRegistrationType != UserRegistrationType.Standard)
                        {
                            return RedirectToAction("RegisterResult", new { resultId = (int)_customerSettings.UserRegistrationType });
                        }

                        //notifications
                        if (_customerSettings.NotifyNewCustomerRegistration)
                            _workflowMessageService.SendCustomerRegisteredNotificationMessage(customer, _localizationSettings.DefaultAdminLanguageId);

                        //send customer welcome message
                        _workflowMessageService.SendCustomerWelcomeMessage(customer, _workContext.WorkingLanguage.Id);


                        _authenticationService.SignIn(customer, true);

                        if (model.RegisterModel.BuyVip != null && model.RegisterModel.BuyVip.Equals("on"))
                        {
                            return RedirectToRoute("CustomerMembership");
                        }

                        if (!String.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
                            return RedirectToRoute("HomePage");
                        //return Redirect(returnUrl);
                        else
                            return RedirectToAction("RegisterSuccess", new { id = customer.Id });

                        //}

                        // Something is wrong, so remove the registered user.
                        //if (_customerService.GetCustomerByEmail(customer.Email) != null)
                        //{
                        //    _customerService.DeleteCustomer(customer);
                        //}
                    }
                    else
                    {
                        foreach (var error in registrationResult.Errors)
                            ModelState.AddModelError("", error);
                    }
                }

            }
            catch (Exception exc)
            {
                ErrorNotification(exc);
            }

            PrepareRegisterModel(model);

            model.RegisterModel.Password = string.Empty;
            model.RegisterModel.ConfirmPassword = string.Empty;

            var loginregistermodel = new LoginRegisterModel();
            loginregistermodel.LoginModel = new LoginModel();
            loginregistermodel.LoginModel.LoginFailed = false;
            loginregistermodel.RegisterModel = model;
            loginregistermodel.IsRegister = true;
            //If we got this far, something failed, redisplay form
            //return View(loginregistermodel);
            return View(model);

        }

        public ActionResult RegisterSuccess(int? id = null)
        {
            if (id.HasValue && id.Value == _workContext.CurrentCustomer.Id)
            {
                return View();
            }
            return RedirectToRoute("HomePage");
        }

        [MobileRedirect]
        public ActionResult RegisterResult(int resultId)
        {
            if (UserRegistrationType.Standard == (UserRegistrationType)resultId)
            {
                return RedirectToAction("Register");
            }

            return View(_localizationService.GetResource("Account.Register.Result.Disabled"));
        }

#if false
        [MobileRedirect]
        public ActionResult PaymentConfirm()
        {
            var processPaymentRequest = _httpContext.Session[PaymentContants.PaymentInfoSessionKey] as ProcessPaymentRequest;
            if (processPaymentRequest != null)
            {
                var customer = _workContext.CurrentCustomer;
                var productVariant = customer.ShoppingCartItems
                    .Where(sci => sci.ShoppingCartType == ShoppingCartType.Logistics)
                    .Single().ProductVariant;

                var model = new SummaryModel();
                model.Address = PrepareAddressModel(customer.ShippingAddress);
                model.BillingAddress = PrepareAddressModel(customer.BillingAddress);
                model.Subtotal = productVariant.Price;
                model.Tax = model.Subtotal * _logisticsInformationSettings.TaxRate;
                var total = model.Subtotal + model.Tax;
                model.Total = model.Subtotal + model.Tax;

                model.MembershipInfo = model.MembershipInfo = string.Format("{0} ({1})", productVariant.Product.Name, productVariant.Name); ;
                model.ExpireDays = GetExpireDays(customer);

                ClearShoppingCart();

                model.PaymentInfo = new SummaryModel.PaymentInfoType()
                {
                    UserName = processPaymentRequest.CreditCardName,
                    CardNumber = processPaymentRequest.CreditCardNumber,
                    CardType = processPaymentRequest.CreditCardType,
                    ExpMonth = processPaymentRequest.CreditCardExpireMonth,
                    ExpYear = processPaymentRequest.CreditCardExpireYear
                };

                _httpContext.Session[PaymentContants.PaymentInfoSessionKey] = null;

                return View(model);
            }

            return RedirectToAction("PaymentInfo");
        }

#endif

        #endregion

        #region Info

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult Info()
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;

            var model = new CustomerInfoModel();
            PrepareCustomerInfoModel(model, customer, false);

            return View(model);
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Info(CustomerInfoModel model)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;

            //email
            if (String.IsNullOrEmpty(model.Email))
                ModelState.AddModelError("", "Email is not provided.");
            //username 
            if (_customerSettings.UsernamesEnabled &&
                this._customerSettings.AllowUsersToChangeUsernames)
            {
                if (String.IsNullOrEmpty(model.Username))
                    ModelState.AddModelError("", "Username is not provided.");
            }

            try
            {
                if (ModelState.IsValid)
                {
                    //username 
                    if (_customerSettings.UsernamesEnabled &&
                        this._customerSettings.AllowUsersToChangeUsernames)
                    {
                        if (!customer.Username.Equals(model.Username.Trim(), StringComparison.InvariantCultureIgnoreCase))
                        {
                            //change username
                            _customerRegistrationService.SetUsername(customer, model.Username.Trim());
                            //re-authenticate
                            _authenticationService.SignIn(customer, true);
                        }
                    }
                    //email
                    if (!customer.Email.Equals(model.Email.Trim(), StringComparison.InvariantCultureIgnoreCase))
                    {
                        //change email
                        _customerRegistrationService.SetEmail(customer, model.Email.Trim());
                        //re-authenticate (if usernames are disabled)
                        if (!_customerSettings.UsernamesEnabled)
                        {
                            _authenticationService.SignIn(customer, true);
                        }
                    }

                    //properties
                    if (_dateTimeSettings.AllowCustomersToSetTimeZone)
                        customer.TimeZoneId = model.TimeZoneId;
                    //VAT number
                    if (_taxSettings.EuVatEnabled)
                    {
                        var prevVatNumber = customer.VatNumber;
                        customer.VatNumber = model.VatNumber;
                        if (prevVatNumber != model.VatNumber)
                        {
                            string vatName = string.Empty;
                            string vatAddress = string.Empty;
                            customer.VatNumberStatus = _taxService.GetVatNumberStatus(customer.VatNumber, out vatName, out vatAddress);
                            //send VAT number admin notification
                            if (!String.IsNullOrEmpty(customer.VatNumber) && _taxSettings.EuVatEmailAdminWhenNewVatSubmitted)
                                _workflowMessageService.SendNewVatSubmittedStoreOwnerNotification(customer, customer.VatNumber, vatAddress, _localizationSettings.DefaultAdminLanguageId);
                        }
                    }
                    //save
                    _customerService.UpdateCustomer(customer);

                    //form fields
                    if (_customerSettings.GenderEnabled)
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Gender, model.Gender);
                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.FirstName, model.FirstName);
                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.LastName, model.LastName);
                    if (_customerSettings.DateOfBirthEnabled)
                    {
                        DateTime? dateOfBirth = null;
                        try
                        {
                            dateOfBirth = new DateTime(model.DateOfBirthYear.Value, model.DateOfBirthMonth.Value, model.DateOfBirthDay.Value);
                        }
                        catch { }
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.DateOfBirth, dateOfBirth);
                    }
                    if (_customerSettings.CompanyEnabled)
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Company, model.Company);
                    if (_customerSettings.StreetAddressEnabled)
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.StreetAddress, model.StreetAddress);
                    if (_customerSettings.StreetAddress2Enabled)
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.StreetAddress2, model.StreetAddress2);
                    if (_customerSettings.ZipPostalCodeEnabled)
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.ZipPostalCode, model.ZipPostalCode);
                    if (_customerSettings.CityEnabled)
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.City, model.City);
                    if (_customerSettings.CountryEnabled)
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.CountryId, model.CountryId);
                    if (_customerSettings.CountryEnabled && _customerSettings.StateProvinceEnabled)
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.StateProvinceId, model.StateProvinceId);
                    if (_customerSettings.PhoneEnabled)
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Phone, model.Phone);
                    if (_customerSettings.CellPhoneEnabled)
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.CellPhone, model.CellPhone);
                    if (_customerSettings.FaxEnabled)
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Fax, model.Fax);

                    //newsletter
                    if (_customerSettings.NewsletterEnabled)
                    {
                        //save newsletter value
                        var newsletter = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmail(customer.Email);
                        if (newsletter != null)
                        {
                            if (model.Newsletter)
                            {
                                newsletter.Active = true;
                                _newsLetterSubscriptionService.UpdateNewsLetterSubscription(newsletter);
                            }
                            else
                                _newsLetterSubscriptionService.DeleteNewsLetterSubscription(newsletter);
                        }
                        else
                        {
                            if (model.Newsletter)
                            {
                                _newsLetterSubscriptionService.InsertNewsLetterSubscription(new NewsLetterSubscription()
                                {
                                    NewsLetterSubscriptionGuid = Guid.NewGuid(),
                                    Email = customer.Email,
                                    Active = true,
                                    CreatedOnUtc = DateTime.UtcNow
                                });
                            }
                        }
                    }

                    if (_forumSettings.ForumsEnabled && _forumSettings.SignaturesEnabled)
                        _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Signature, model.Signature);

                    return RedirectToRoute("CustomerInfo");
                }
            }
            catch (Exception exc)
            {
                ModelState.AddModelError("", exc.Message);
            }


            //If we got this far, something failed, redisplay form
            PrepareCustomerInfoModel(model, customer, true);
            return View(model);
        }

        #endregion

        #region Renew
#if false
        [MobileRedirect]
        public ActionResult Renew()
        {
            return AccessDeniedView();
            var customer = _workContext.CurrentCustomer;
            if (!_permissionService.Authorize(StandardPermissionProvider.AccessLogistics, customer))
            {
                return AccessDeniedView();
            }

            if (customer.ShippingAddress == null)
            {
                return FatalErrorView("The customer shipping address doesn't exist.", customer);
            }

            var model = new LogisticsRenewModel();
            model.Accepted = false;
            model.MembershipOptions = PrepareMembershipOptions();
            if (!model.SelectedProductVariantId.HasValue)
            {
                model.SelectedProductVariantId = model.MembershipOptions.First().ProductVariantId;
            }

            model.History = PrepareMembershipHistory(customer);
            model.MembershipExpireDays = GetExpireDays(customer);
            model.Address = PrepareAddressModel(customer.ShippingAddress);
            model.Address.AllowEmpty = true;

            if (customer.BillingAddress == null)
            {
                model.BillingAddress.AllowEmpty = true;
            }
            else if (customer.ShippingAddress.Id == customer.BillingAddress.Id)
            {
                model.BillingAddress.AllowEmpty = true;
            }
            else
            {
                model.BillingAddress = PrepareAddressModel(customer.BillingAddress);
            }
            return View(model);
        }

        private IList<LogisticsRenewModel.MemberPurchaseRecord> PrepareMembershipHistory(Customer customer)
        {
            var orders = _orderService.GetOrdersByCustomerId(customer.Id);
            var options = _logisticsInformationSettings.LoadMembershipOptions();
            var pvIds = options.Select(o => o.ProductVariantId);
            orders = orders.Where(o => o.OrderProductVariants.Any(pv => pvIds.Contains(pv.ProductVariantId))).ToList();

            var records = orders.Select(o => new LogisticsRenewModel.MemberPurchaseRecord()
            {
                Date = o.CreatedOnUtc,
                MemberType = o.OrderProductVariants.Single().ProductVariant.Name,
                Days = options.Single(x => o.OrderProductVariants.Single().ProductVariantId == x.ProductVariantId).Value
            });
            return records.ToList();
        }

        private int GetExpireDays(Customer customer)
        {
            var expireDate = customer.GetAttribute<DateTime?>(
                SystemCustomerAttributeNames.LogisticsMemberExpireDateTimeOnUtc, _genericAttributeService);
            int days = 0;
            if (expireDate.HasValue)
            {
                if (expireDate <= DateTime.UtcNow)
                {
                    _genericAttributeService.SaveAttribute<DateTime?>(customer, SystemCustomerAttributeNames.LogisticsMemberExpireDateTimeOnUtc, null);
                    return 0;
                }
                else
                {
                    days = (expireDate.Value - DateTime.UtcNow).Days;
                    if (days < 0)
                        days = 0;
                    else
                    {
                        days += 1;
                    }
                }
            }
            return days;
        }

        [HttpPost]
        public ActionResult Renew(LogisticsRenewModel model)
        {
            return AccessDeniedView();
#if false
            var customer = _workContext.CurrentCustomer;
            if (!_permissionService.Authorize(StandardPermissionProvider.AccessLogistics, customer))
            {
                return AccessDeniedView();
            }

            if (customer.ShippingAddress == null)
            {
                _authenticationService.SignOut();
                return RedirectToRoute("HomePage");
            }

            if (ModelState.IsValid)
            {
                if (!model.BillingAddress.AllowEmpty)
                {
                    Address address = new Address();
                    address.FirstName = model.BillingAddress.FirstName;
                    address.LastName = model.BillingAddress.LastName;
                    address.Address2 = model.BillingAddress.Address2;
                    address.PhoneNumber = model.BillingAddress.PhoneNumber;
                    address.CellPhoneNumber = model.BillingAddress.CellPhoneNumber;

                    address.Email = model.BillingAddress.Email;
                    address.Company = model.BillingAddress.Company;
                    address.CountryId = customer.ShippingAddress.CountryId;
                    address.StateProvinceId = customer.ShippingAddress.StateProvinceId;
                    address.City = model.BillingAddress.City;
                    address.Address1 = model.BillingAddress.Address1;
                    address.ZipPostalCode = model.BillingAddress.ZipPostalCode;

                    _addressService.InsertAddress(address);
                    customer.Addresses.Add(address);
                    customer.BillingAddress = address;
                    _customerService.UpdateCustomer(customer);
                }

                AddMembershipToCart(model.SelectedProductVariantId.Value);

                return RedirectToAction("RenewPaymentInfo");
            }

            model.MembershipOptions = PrepareMembershipOptions();
            model.History = PrepareMembershipHistory(customer);
            model.MembershipExpireDays = GetExpireDays(customer);
            model.Address = PrepareAddressModel(customer.ShippingAddress);

            return View(model);
#endif
        }


        [NopHttpsRequirement(SslRequirement.Yes)]
        [MobileRedirect]
        public ActionResult RenewPaymentInfo()
        {
            var customer = _workContext.CurrentCustomer;
            //validation
            var cart = customer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.Logistics).ToList();
            if (cart.Count != 1)
            {
                ClearShoppingCart();
                return RedirectToAction("Index", "Order");
            }

            //model
            var model = new SummaryModel();
            var pv = cart.Single().ProductVariant;
            model.Address = PrepareAddressModel(customer.ShippingAddress);
            model.Subtotal = pv.Price;
            model.Tax = model.Subtotal * _logisticsInformationSettings.TaxRate;
            var total = model.Subtotal + model.Tax;
            model.Total = model.Subtotal + model.Tax;

            model.BillingAddress = PrepareAddressModel(customer.BillingAddress);
            model.MembershipInfo = model.MembershipInfo = string.Format("{0} ({1})", pv.Product.Name, pv.Name);
            var processPaymentRequest = new ProcessPaymentRequest()
            {
                OrderTotal = total
            };
            _httpContext.Session[PaymentContants.PaymentInfoSessionKey] = processPaymentRequest;
            SavePaymentInformation(total, customer);
            return View("PaymentInfo", model);
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult RenewPaymentInfo(FormCollection form)
        {
            var customer = _workContext.CurrentCustomer;
            //validation
            var cart = customer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.Logistics).ToList();
            if (cart.Count != 1)
            {
                ClearShoppingCart();
                return RedirectToAction("Index", "Order");
            }

            try
            {
                if (ModelState.IsValid)
                {
                    if (form["succeeded"] == "succeeded")
                    {
                        RemovePaymentInformation(customer);
                        PlaceOrder(customer);

                        ExtendMembership(customer);

                        return RedirectToAction("PaymentConfirm");
                    }
                }

                //If we got this far, something failed, redisplay form
                //model
                var model = new SummaryModel();
                var pv = customer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.Logistics)
                    .Single().ProductVariant;
                model.Address = PrepareAddressModel(_workContext.CurrentCustomer.ShippingAddress);
                model.Subtotal = pv.Price;
                model.Tax = model.Subtotal * _logisticsInformationSettings.TaxRate;
                var total = model.Subtotal + model.Tax;
                model.Total = model.Subtotal + model.Tax;
                model.MembershipInfo = string.Format("{0} ({1})", pv.Product.Name, pv.Name);

                var processPaymentRequest = new ProcessPaymentRequest()
                {
                    OrderTotal = total
                };
                _httpContext.Session[PaymentContants.PaymentInfoSessionKey] = processPaymentRequest;
                SavePaymentInformation(total, customer);
                return View("PaymentInfo", model);
            }
            catch (Exception e)
            {
                return FatalErrorView(e.Message, customer, e);
            }
        }
#endif

        #endregion

        #region Membership

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult Membership()
        {
            var customer = _workContext.CurrentCustomer;
            if (customer.IsGuest()) return RedirectToAction("Login");
            var model = PrepareCustomerMembershipModel(customer);
            return View(model);

        }

        [HttpPost]
        public ActionResult PaymentMethod(FormCollection form)
        {
            int selectedMembershipId = 0;
            if (!string.IsNullOrEmpty(form["SelectedMembershipOptionId"]))
            {
                if (!int.TryParse(form["SelectedMembershipOptionId"], out selectedMembershipId))
                    return RedirectToAction("CustomerMembership");
            }
            else
            {
                return RedirectToAction("CustomerMembership");
            }


            var model = PreparePaymentMethodModel(selectedMembershipId);
            var html = "";
            if (model != null)
                html = this.RenderPartialViewToString("PaymentMethod", model);
            return Json(new
            {
                success = true,
                html = html,
                message = RenderAjaxNotification()
            });
        }

        public ActionResult SavePaymentMethod(FormCollection form)
        {
            if (_workContext.CurrentCustomer.IsGuest())
                throw new Exception("Anonymous is not allowed");

            string paymentMethod = form["paymentmethod"];
            //payment method 
            if (String.IsNullOrEmpty(paymentMethod))
                throw new Exception("Selected payment method can't be parsed");

            //var model = new MembershipPaymentMethodModel();
            //TryUpdateModel(model);

            var paymentMethodInst = _paymentService.LoadPaymentMethodBySystemName(paymentMethod);
            if (paymentMethodInst == null || !paymentMethodInst.IsPaymentMethodActive(_paymentSettings))
                throw new Exception("Selected payment method can't be parsed");

            //save
            _workContext.CurrentCustomer.SelectedPaymentMethodSystemName = paymentMethod;
            _customerService.UpdateCustomer(_workContext.CurrentCustomer);

            var paymenInfoModel = PreparePaymentInfoModel(paymentMethodInst, GetStoreId());

            var html = "";
            if (paymenInfoModel != null)
                html = this.RenderPartialViewToString("ShowPaymentInfo", paymenInfoModel);

            return Json(new
            {
                html = html,
                message = RenderAjaxNotification()
            });
        }

        public ActionResult SavePaymentInfo(FormCollection form, int StoreId = 1)
        {
            if ((_workContext.CurrentCustomer.IsGuest() && !_orderSettings.AnonymousCheckoutAllowed))
                throw new Exception("Anonymous checkout is not allowed");

            var paymentMethod = _paymentService.LoadPaymentMethodBySystemName(_workContext.CurrentCustomer.SelectedPaymentMethodSystemName);
            if (paymentMethod == null)
                throw new Exception("Payment method is not selected");
            var paymentControllerType = paymentMethod.GetControllerType();
            var paymentController = DependencyResolver.Current.GetService(paymentControllerType) as BaseNopPaymentController;
            var warnings = paymentController.ValidatePaymentForm(form);
            foreach (var warning in warnings)
                ModelState.AddModelError("", warning);
            if (ModelState.IsValid)
            {
                //get payment info
                var paymentInfo = paymentController.GetPaymentInfo(form);

                paymentInfo.PaymentMethodSystemName = _workContext.CurrentCustomer.SelectedPaymentMethodSystemName;
                if (_httpContext.Session["membership_selectedProductVariantId"] != null)
                {
                    //var productVariantId = int.Parse(form["SelectedVariantId"]);
                    var productVariant =
                        _productService.GetProductVariantById(
                            (int)_httpContext.Session["membership_selectedProductVariantId"]);

                    var cart = new List<ShoppingCartItem>(){ 
                        new ShoppingCartItem{ 
                            ProductVariantId = productVariant.Id, 
                            Quantity = 1, 
                            ShoppingCartType= ShoppingCartType.ShoppingCart,
                            CustomerId = _workContext.CurrentCustomer.Id,
							Customer = _workContext.CurrentCustomer,
                            ProductVariant = productVariant
                        }};

                    decimal? orderTotal = null;
                    decimal orderDiscountAmount = decimal.Zero;
                    Discount orderAppliedDiscount = null;
                    List<AppliedGiftCard> appliedGiftCards = null;
                    int redeemedRewardPoints = 0;
                    decimal redeemedRewardPointsAmount = decimal.Zero;
                    List<TaxSurcharge> taxRate;
                    orderTotal = _orderTotalCalculationService.GetShoppingCartTotal(cart,
                            out orderDiscountAmount, out orderAppliedDiscount, out appliedGiftCards,
                            out redeemedRewardPoints, out redeemedRewardPointsAmount, out taxRate);

                    paymentInfo.OrderTotal = orderTotal.Value;
                    var result = _orderProcessingService.PlaceOrder(paymentInfo); //Only process payment
                    if (result.Success)
                    {
                        AddMembershipToCustomer(productVariant);
                        var model = PrepareCustomerMembershipModel(_workContext.CurrentCustomer);
                        return new JsonResult() { Data = this.RenderPartialViewToString("MembershipStatus", model), ContentType = "application/json" };
                    }
                    else
                    {
                        return new JsonResult() { Data = new { Errors = result.Errors }, ContentType = "application/json" };
                    }
                }
            }

            return new JsonResult();
        }

        [NonAction]
        private void AddMembershipToCustomer(ProductVariant productVariant)
        {
            var paidMembership = _customerService.GetAllClubMemberships().FirstOrDefault(cm => cm.ProductVariantId == productVariant.Id);
            if (paidMembership == null)
            {
                throw new ArgumentException("Invalid product variant that does not match the membership");
            }
            _customerService.InsertMembershipHistory(new ClubMembershipHistory
            {
                CustomerId = _workContext.CurrentCustomer.Id,
                MembershipId = paidMembership.Id,
                CreatedDateTime = DateTime.UtcNow
            });

            var existingRoles = _workContext.CurrentCustomer.CustomerRoleMappings.Where(mapping => mapping.CustomerRoleId == paidMembership.CustomerRoleId);
            if (existingRoles.Any())
            {
                var existingRole = existingRoles.First();
                existingRole.EndDate = GetEndDate(existingRole.EndDate, paidMembership);
            }
            else
            {
                _workContext.CurrentCustomer.CustomerRoleMappings.Add(
                    new CustomerRoleMapping()
                    {
                        CustomerId = _workContext.CurrentCustomer.Id,
                        Customer = _workContext.CurrentCustomer,
                        CustomerRoleId = paidMembership.CustomerRoleId,
                        CustomerRole = paidMembership.CustomerRole,
                        StartDate = DateTime.UtcNow,
                        EndDate = GetEndDate(null, paidMembership)
                    });
            }
            _customerService.UpdateCustomer(_workContext.CurrentCustomer);
        }

        [NonAction]
        private void GetCurrency(Customer customer, ref string customerCurrencyCode, ref decimal customerCurrencyRate)
        {
            var customerCurrency = (customer.Currency != null && customer.Currency.Published) ? customer.Currency : _workContext.WorkingCurrency;
            customerCurrencyCode = customerCurrency.CurrencyCode;
            var primaryStoreCurrency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId);
            customerCurrencyRate = customerCurrency.Rate / primaryStoreCurrency.Rate;
        }

        [NonAction]
        private CustomerMembershipModel PrepareCustomerMembershipModel(Customer customer)
        {
            var model = new CustomerMembershipModel();
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Membership;

            var memberships = _customerService.GetAllClubMemberships().Where(m => m.ProductVariantId.HasValue && m.ProductVariantId.Value > 0).ToList();
            var currentRole = customer.CustomerRoleMappings.FirstOrDefault(crm => (!crm.EndDate.HasValue || crm.EndDate > DateTime.UtcNow)
                    && crm.CustomerRole.SystemName == SystemCustomerRoleNames.DreamFactoryUser);

            if (currentRole != null)
            {
                model.CurrentMembership = PrepareMembershipModel(memberships.FirstOrDefault(cm => cm.CustomerRoleId == currentRole.CustomerRoleId));
                if (currentRole != null && currentRole.EndDate.HasValue)
                {
                    model.ExpireDate = currentRole.EndDate.Value;
                    model.ExpireDays = (currentRole.EndDate.Value - DateTime.UtcNow).Days;
                }
            }
            model.MembershipOptions = PrepareMembershipModel(memberships);
            return model;
        }

        [NonAction]
        protected MembershipPaymentInfoModel PreparePaymentInfoModel(IPaymentMethod paymentMethod, int? storeId = null)
        {
            var model = new MembershipPaymentInfoModel();
            string actionName;
            string controllerName;
            RouteValueDictionary routeValues;
            paymentMethod.GetPaymentInfoRoute(out actionName, out controllerName, out routeValues);
            model.PaymentInfoActionName = actionName;
            model.PaymentInfoControllerName = controllerName;
            model.PaymentInfoRouteValues = routeValues;
            model.ShowSubmitButton = true;
            model.PaymentInfoRouteValues.Add("customerId", _workContext.CurrentCustomer.Id);
            model.PaymentInfoRouteValues.Add("storeId", GetStoreId());
            model.PaymentInfoRouteValues.Add("returnRouteName", "CustomerMembershipSavePaymentInfo");

            return model;
        }

        [NonAction]
        protected MembershipPaymentMethodModel PreparePaymentMethodModel(int selectedMembershipId)
        {
            var model = new MembershipPaymentMethodModel();
            var boundPaymentMethods = _paymentService
             .LoadActivePaymentMethods(_workContext.CurrentCustomer.Id)
             .Where(pm =>
                 pm.PaymentMethodType == PaymentMethodType.Standard ||
                 pm.PaymentMethodType == PaymentMethodType.Redirection)
             .ToList();
            var membership = _customerService.GetAllClubMemberships().FirstOrDefault(m => m.Id == selectedMembershipId);
            if (membership == null)
            {
                return null;
            }
            var productVariant = membership.ProductVariant;
            _httpContext.Session["membership_selectedProductVariantId"] = productVariant.Id;
            var cart = new List<ShoppingCartItem>();
            if (productVariant != null)
            {
                cart.Add(new ShoppingCartItem
                {
                    Customer = _workContext.CurrentCustomer,
                    CustomerId = _workContext.CurrentCustomer.Id,
                    ProductVariant = productVariant,
                    ProductVariantId = productVariant.Id,
                    Quantity = 1,
                    ShoppingCartType = ShoppingCartType.ShoppingCart,
                    ShoppingCartTypeId = (int)ShoppingCartType.ShoppingCart
                });
            }

            foreach (var pm in boundPaymentMethods)
            {
                var pmModel = new MembershipPaymentMethodModel.PaymentMethodModel()
                {
                    Name = pm.GetLocalizedFriendlyName(_localizationService, _workContext.WorkingLanguage.Id),
                    PaymentMethodSystemName = pm.PluginDescriptor.SystemName,
                };


                decimal paymentMethodAdditionalFee = _paymentService.GetAdditionalHandlingFee(cart, pm.PluginDescriptor.SystemName);
                decimal rateBase = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, _workContext.CurrentCustomer);
                decimal rate = _currencyService.ConvertFromPrimaryStoreCurrency(rateBase, _workContext.WorkingCurrency);
                if (rate > decimal.Zero)
                    pmModel.Fee = _priceFormatter.FormatPaymentMethodAdditionalFee(rate, true);

                model.PaymentMethods.Add(pmModel);
            }

            if (!String.IsNullOrEmpty(_workContext.CurrentCustomer.SelectedPaymentMethodSystemName))
            {
                var paymentMethodToSelect = model.PaymentMethods.ToList()
                    .Find(pm => pm.PaymentMethodSystemName.Equals(_workContext.CurrentCustomer.SelectedPaymentMethodSystemName, StringComparison.InvariantCultureIgnoreCase));
                if (paymentMethodToSelect != null)
                    paymentMethodToSelect.Selected = true;
            }

            if (model.PaymentMethods.Where(so => so.Selected).FirstOrDefault() == null)
            {
                var paymentMethodToSelect = model.PaymentMethods.FirstOrDefault();
                if (paymentMethodToSelect != null)
                    paymentMethodToSelect.Selected = true;
            }

            return model;
        }

        #endregion

        #region Change password

        [NopHttpsRequirement(SslRequirement.Yes)]
        [MobileRedirect]
        public ActionResult ChangePassword()
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;

            var model = new ChangePasswordModel();
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.ChangePassword;
            return View(model);
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult ChangePassword(ChangePasswordModel model)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.ChangePassword;
            if (ModelState.IsValid)
            {
                var changePasswordRequest = new ChangePasswordRequest(customer.Email,
                    true, _customerSettings.DefaultPasswordFormat, model.NewPassword, model.OldPassword);
                var changePasswordResult = _customerRegistrationService.ChangePassword(changePasswordRequest);
                if (changePasswordResult.Success)
                {
                    model.Result = _localizationService.GetResource("Account.ChangePassword.Success");
                    AddSuccessMessage(model.Result);
                    return View(model);
                }
                else
                {
                    foreach (var error in changePasswordResult.Errors)
                        ModelState.AddModelError("", error);
                }
            }
            AddModelStateErrorMessages();
            //If we got this far, something failed, redisplay form
            return View(model);
        }

        #endregion

        #region Password recovery

        [NopHttpsRequirement(SslRequirement.Yes)]
        [MobileRedirect]
        public ActionResult PasswordRecovery()
        {
            var customer = _workContext.CurrentCustomer;

            var model = new PasswordRecoveryModel();
            model.NavigationModel = GetCustomerNavigationModel(customer);
            if (!customer.IsRegistered())
            {
                model.NavigationModel.HidePasswordRecovery = false;
                model.NavigationModel.HideShipping = true;
                model.NavigationModel.HideShopping = true;
            }
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.PasswordRecovery;
            return View(model);
        }

        [HttpPost, ActionName("PasswordRecovery")]
        [FormValueRequired("send-email")]
        public ActionResult PasswordRecoverySend(PasswordRecoveryModel model)
        {
            var customer = _workContext.CurrentCustomer;
            model.NavigationModel = GetCustomerNavigationModel(customer);
            if (!customer.IsRegistered())
            {
                model.NavigationModel.HidePasswordRecovery = false;
                model.NavigationModel.HideShipping = true;
                model.NavigationModel.HideShopping = true;
            }
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.PasswordRecovery;
            model.Found = false;
            customer = _customerService.GetCustomerByEmail(model.Email);
            if (ModelState.IsValid)
            {
                if (customer != null && customer.Active && !customer.Deleted)
                {
                    var passwordRecoveryToken = Guid.NewGuid();
                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.PasswordRecoveryToken, passwordRecoveryToken.ToString());
                    _workflowMessageService.SendCustomerPasswordRecoveryMessage(customer, _workContext.WorkingLanguage.Id);
                    model.Found = true;
                    model.Result = _localizationService.GetResource("Account.PasswordRecovery.EmailHasBeenSent");
                }
                else
                    model.Result = _localizationService.GetResource("Account.PasswordRecovery.EmailNotFound");

                return View(model);
            }

            //If we got this far, something failed, redisplay form
            return View(model);
        }

        [NopHttpsRequirement(SslRequirement.Yes)]
        [MobileRedirect]
        public ActionResult PasswordRecoveryConfirm(string token, string email)
        {
            var customer = _customerService.GetCustomerByEmail(email);
            if (customer == null)
                return RedirectToRoute("HomePage");

            var cPrt = customer.GetAttribute<string>(SystemCustomerAttributeNames.PasswordRecoveryToken);
            if (String.IsNullOrEmpty(cPrt))
                return RedirectToRoute("HomePage");

            if (!cPrt.Equals(token, StringComparison.InvariantCultureIgnoreCase))
                return RedirectToRoute("HomePage");

            var model = new PasswordRecoveryConfirmModel();
            customer = _workContext.CurrentCustomer;
            model.NavigationModel = GetCustomerNavigationModel(customer);
            if (!customer.IsRegistered())
            {
                model.NavigationModel.HidePasswordRecovery = false;
                model.NavigationModel.HideShipping = true;
                model.NavigationModel.HideShopping = true;
            }
            return View(model);
        }

        [HttpPost, ActionName("PasswordRecoveryConfirm")]
        [FormValueRequired("set-password")]
        public ActionResult PasswordRecoveryConfirmPOST(string token, string email, PasswordRecoveryConfirmModel model)
        {
            var customer = _customerService.GetCustomerByEmail(email);
            if (customer == null)
                return RedirectToRoute("HomePage");

            model.NavigationModel = GetCustomerNavigationModel(customer);
            if (!customer.IsRegistered())
            {
                model.NavigationModel.HidePasswordRecovery = false;
                model.NavigationModel.HideShipping = true;
                model.NavigationModel.HideShopping = true;
            }

            var cPrt = customer.GetAttribute<string>(SystemCustomerAttributeNames.PasswordRecoveryToken);
            if (String.IsNullOrEmpty(cPrt))
                return RedirectToRoute("HomePage");

            if (!cPrt.Equals(token, StringComparison.InvariantCultureIgnoreCase))
                return RedirectToRoute("HomePage");

            if (ModelState.IsValid)
            {
                var response = _customerRegistrationService.ChangePassword(new ChangePasswordRequest(email,
                    false, _customerSettings.DefaultPasswordFormat, model.NewPassword));
                if (response.Success)
                {
                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.PasswordRecoveryToken, "");

                    model.SuccessfullyChanged = true;
                    model.Result = _localizationService.GetResource("Account.PasswordRecovery.PasswordHasBeenChanged");
                    //sign in new customer
                    _authenticationService.SignIn(customer, false);
                    //activity log
                    _customerActivityService.InsertActivity("Logistics.Login", _localizationService.GetResource("ActivityLog.PublicStore.Login"), customer);
                }
                else
                {
                    model.Result = response.Errors.FirstOrDefault();
                }

                return View(model);
            }

            //If we got this far, something failed, redisplay form
            return View(model);
        }

        #endregion

        #region Logout

        public ActionResult Logout()
        {
            if (_workContext.OriginalCustomerIfImpersonated != null)
            {
                //logout impersonated customer
                _genericAttributeService.SaveAttribute<int?>(_workContext.OriginalCustomerIfImpersonated,
                    SystemCustomerAttributeNames.ImpersonatedCustomerId, null);
                //redirect back to customer details page (admin area)
                return this.RedirectToAction("Edit", "Customer", new { id = _workContext.CurrentCustomer.Id, area = "Admin" });

            }
            else
            {
                //remove cookies or settings on logout
                if (Request.Cookies["logistics-" + _workContext.CurrentCustomer.Id] != null)
                {
                    HttpCookie logisticsCookie = new HttpCookie("logistics-" + _workContext.CurrentCustomer.Id);
                    logisticsCookie.Expires = DateTime.Now.AddDays(-1d);
                    Response.Cookies.Add(logisticsCookie);
                }


                //activity log
                _customerActivityService.InsertActivity("Logistics.Logout", _localizationService.GetResource("ActivityLog.PublicStore.Logout"));

                _authenticationService.SignOut();
                return RedirectToRoute("HomePage");
            }
        }

        #endregion

        #region Avatar

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult Avatar()
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            if (!_customerSettings.AllowCustomersToUploadAvatars)
                return RedirectToRoute("CustomerInfo");

            var customer = _workContext.CurrentCustomer;

            var model = new CustomerAvatarModel();
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Avatar;
            model.AvatarUrl = _pictureService.GetPictureUrl(
                customer.GetAttribute<int>(SystemCustomerAttributeNames.AvatarPictureId),
                _mediaSettings.AvatarPictureSize,
                false);
            return View(model);
        }

        [HttpPost, ActionName("Avatar")]
        [FormValueRequired("upload-avatar")]
        public ActionResult UploadAvatar(CustomerAvatarModel model, HttpPostedFileBase uploadedFile)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            if (!_customerSettings.AllowCustomersToUploadAvatars)
                return RedirectToRoute("CustomerInfo");

            var customer = _workContext.CurrentCustomer;

            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Avatar;


            if (ModelState.IsValid)
            {
                try
                {
                    var customerAvatar = _pictureService.GetPictureById(customer.GetAttribute<int>(SystemCustomerAttributeNames.AvatarPictureId));
                    if ((uploadedFile != null) && (!String.IsNullOrEmpty(uploadedFile.FileName)))
                    {
                        int avatarMaxSize = _customerSettings.AvatarMaximumSizeBytes;
                        if (uploadedFile.ContentLength > avatarMaxSize)
                            throw new NopException(string.Format(_localizationService.GetResource("Account.Avatar.MaximumUploadedFileSize"), avatarMaxSize));

                        byte[] customerPictureBinary = uploadedFile.GetPictureBits();
                        if (customerAvatar != null)
                            customerAvatar = _pictureService.UpdatePicture(customerAvatar.Id, customerPictureBinary, uploadedFile.ContentType, null, true);
                        else
                            customerAvatar = _pictureService.InsertPicture(customerPictureBinary, uploadedFile.ContentType, null, true);
                    }

                    int customerAvatarId = 0;
                    if (customerAvatar != null)
                        customerAvatarId = customerAvatar.Id;

                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.AvatarPictureId, customerAvatarId);

                    model.AvatarUrl = _pictureService.GetPictureUrl(
                        customer.GetAttribute<int>(SystemCustomerAttributeNames.AvatarPictureId),
                        _mediaSettings.AvatarPictureSize,
                        false);
                    return View(model);
                }
                catch (Exception exc)
                {
                    ModelState.AddModelError("", exc.Message);
                }
            }


            //If we got this far, something failed, redisplay form
            model.AvatarUrl = _pictureService.GetPictureUrl(
                customer.GetAttribute<int>(SystemCustomerAttributeNames.AvatarPictureId),
                _mediaSettings.AvatarPictureSize,
                false);
            return View(model);
        }

        [HttpPost, ActionName("Avatar")]
        [FormValueRequired("remove-avatar")]
        public ActionResult RemoveAvatar(CustomerAvatarModel model, HttpPostedFileBase uploadedFile)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            if (!_customerSettings.AllowCustomersToUploadAvatars)
                return RedirectToRoute("CustomerInfo");

            var customer = _workContext.CurrentCustomer;

            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Avatar;

            var customerAvatar = _pictureService.GetPictureById(customer.GetAttribute<int>(SystemCustomerAttributeNames.AvatarPictureId));
            if (customerAvatar != null)
                _pictureService.DeletePicture(customerAvatar);
            _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.AvatarPictureId, 0);

            return RedirectToRoute("CustomerAvatar");
        }

        #endregion

        #region CalculateRate

        public ActionResult CalculateRate()
        {
            // We use action defined in logistics instead
            var customer = _workContext.CurrentCustomer;
            var model = GetCustomerNavigationModel(customer);
            model.SelectedTab = CustomerNavigationEnum.CalculateCost;
            return View(model);
        }

        #endregion

        #region Tracking

        [HttpGet]
        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult Tracking()
        {
            var customer = _workContext.CurrentCustomer;
            var model = PrepareTrackingModel(customer);
            model.IsAuthenticated = IsCurrentUserRegistered();
            return View(model);
        }

        [GridAction(EnableCustomBinding = true)]
        public ActionResult TrackingPackageList(GridCommand command, CustomerTrackingModel model)
        {
            var customer = _workContext.CurrentCustomer;
            var customerId = customer.Id;
            // See if search matches pattern
            if (!String.IsNullOrEmpty(model.TrackingNumber))
            {
                var regex = _logisticsInformationSettings.TrackingNumberRegex;
                if (!String.IsNullOrEmpty(regex))
                {
                    Regex r = new Regex(regex, RegexOptions.IgnoreCase);
                    Match m = r.Match(model.TrackingNumber);
                    if (m.Success)
                    {
                        // If matched, no need to limit to the user placing the order
                        customerId = 0;
                        // If user enter the TrackingNumber it should be searched  without the days
                        model.TrackingDays = 0;
                    }
                }
            }
            if (command.PageSize == 0 || command.PageSize > 25)
                command.PageSize = 25;
            var orderHistoryInMonths = _logisticsInformationSettings.OrderHistoryInMonths == 0 ? 2 : _logisticsInformationSettings.OrderHistoryInMonths;
            DateTime? startDate = model.TrackingDays.HasValue ? DateTime.UtcNow.AddDays(model.TrackingDays.Value * -1) : DateTime.UtcNow.AddMonths(orderHistoryInMonths);
            DateTime? endDate = DateTime.UtcNow;
            if (model.TrackingDays.HasValue && model.TrackingDays.Value == 0)
                startDate = null;

            var pkgs = _logisticsService.SearchTrackingPackagesByCustomerId(
                customerId,
                startDate,
                endDate,
                model.TrackingNumber,
                command.Page - 1,
                command.PageSize,
                _logisticsInformationSettings.TrackingIncludeDelivered);

            var gridModel = new GridModel<CustomerTrackingModel.TrackingPackageModel>
            {
                Data = pkgs.Select(PrepareTrackingPackageModel),
                Total = pkgs.TotalCount
            };
            return View(gridModel);
        }

        [HttpPost, ActionName("Tracking")]
        [FormValueRequired(FormValueRequirement.StartsWith, "cancelPackage")]
        public ActionResult PackageCancel(int shipmentId)
        {
            var customer = _workContext.CurrentCustomer;
            var shipment = _shipmentService.GetShipmentById(shipmentId);

            if (shipment == null || shipment.Order == null)
                return RedirectToAction("Tracking");

            var package = _logisticsService.GetPackageByShipmentId(shipmentId);
            if (package == null)
                return RedirectToAction("Tracking");

            if (shipment.Order.Customer.Id != customer.Id)
                return new HttpUnauthorizedResult();

            var handle = _logisticsProcessingService.CreatePackageHandle(package);

            if (handle.CanCancel())
            {
                handle.Cancel();
                SuccessNotification(_localizationService.GetResource("Customer.Tracking.PackageCancelled"));
            }
            return RedirectToAction("Tracking");
        }

        [HttpPost, ActionName("Tracking")]
        [FormValueRequired(FormValueRequirement.StartsWith, "changePickupAddress")]
        public ActionResult PackageChangePickupAddress(int shipmentId)
        {
            var customer = _workContext.CurrentCustomer;
            var shipment = _shipmentService.GetShipmentById(shipmentId);

            if (shipment == null || shipment.Order == null)
                return RedirectToAction("Tracking");

            var package = _logisticsService.GetPackageByShipmentId(shipmentId);
            if (package == null)
                return RedirectToAction("Tracking");

            if (shipment.Order.Customer.Id != customer.Id)
                return new HttpUnauthorizedResult();

            var handle = _logisticsProcessingService.CreatePackageHandle(package);

            if (handle.CanChangePickupAddress())
            {
                return RedirectToAction("AddressEditChange", new { addressId = package.PickUpLocation.AddressId, shipmentId = shipmentId, addressType = "PickupAddress" });
            }
            return RedirectToAction("Tracking");
        }

        [HttpPost, ActionName("Tracking")]
        [FormValueRequired(FormValueRequirement.StartsWith, "changeDeliveryAddress")]
        public ActionResult PackageChangeDeliveryAddress(int shipmentId)
        {
            var customer = _workContext.CurrentCustomer;
            var shipment = _shipmentService.GetShipmentById(shipmentId);

            if (shipment == null || shipment.Order == null)
                return RedirectToAction("Tracking");

            var package = _logisticsService.GetPackageByShipmentId(shipmentId);
            if (package == null)
                return RedirectToAction("Tracking");

            if (shipment.Order.Customer.Id != customer.Id)
                return new HttpUnauthorizedResult();

            var handle = _logisticsProcessingService.CreatePackageHandle(package);

            if (handle.CanChangePickupAddress())
            {
                if (handle.IsChangeDeliveryAddressFree())
                {
                    return RedirectToAction("AddressEditChange", new { addressId = package.DeliveryLocation.AddressId, shipmentId = shipmentId, addressType = "DeliveryAddress" });
                }
                else
                {
                    var total = _logisticsInformationSettings.AdditionalDeliveryCharge;
                    //_orderlogisticsProcessingService.SavePaymentInformation(total, customer);
                    return RedirectToAction("PaymentInfo", new { returnUrl = Url.Action("AddressEditChange", new { addressId = package.DeliveryLocation.AddressId, shipmentId = shipmentId, addressType = "DeliveryAddress" }) });
                }
            }

            return RedirectToAction("Tracking");
        }

        [HttpPost]
        public ActionResult CancelPackage(int orderID, int shipmentId)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders))
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;

            var order = _orderService.GetOrderById(orderID);
            if (order == null || order.OrderKind != OrderKind.Express)
                return RedirectToAction("CustomerTracking");

            var shipment = order.Shipments.Where(s => s.Id == shipmentId).FirstOrDefault();
            if (shipment != null)
            {
                var pkg = _logisticsService.GetPackageByShipmentId(shipment.Id);
                try
                {
                    if (_logisticsProcessingService.CanCancelPackage(pkg))
                    {
                        if (_logisticsProcessingService.CancelPackage(pkg))
                        {
                            SuccessNotification(_localizationService.GetResource("Admin.Orders.Shipments.PackageCancelled"));
                            _customerActivityService.InsertActivity("CancelOrder", _localizationService.GetResource("ActivityLog.CancelPackage"), pkg.Id);
                        }
                    }
                }
                catch (Exception exc)
                {
                    ErrorNotification(exc, true);
                    return RedirectToRoute("CustomerTracking");
                }
            }

            return Json(new
            {
                redirectUrl = Url.Action("Tracking", "Customer"),
                isRedirect = true
            });
        }

        #endregion

        #region Orders

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult Orders(int? orderId = null)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;
            var model = PrepareCustomerOrderListModel(customer);
            model.OrderId = orderId;

            model.OrderDaysOptions = new List<SelectListItem>();
            model.OrderDaysOptions.Add(new SelectListItem()
            {
                Value = "1",
                Text = "Last 30 Days",
                Selected = true
            });
            model.OrderDaysOptions.Add(new SelectListItem()
            {
                Value = "2",
                Text = "Last 90 Days"
            });
            model.OrderDaysOptions.Add(new SelectListItem()
            {
                Value = "3",
                Text = "Last 180 Days"
            });
            var now = DateTime.UtcNow;
            for (var i = 0; i > -24; i--)
            {
                var newMonthDate = now.AddMonths(i);
                model.OrderDaysOptions.Add(new SelectListItem()
                {
                    Value = i.ToString(),
                    Text = newMonthDate.Year.ToString() + " " + newMonthDate.ToString("MMMM")
                });
            }

            model.OrderStatusOptions.Add(new SelectListItem()
            {
                Value = "0",
                Text = "All",
                Selected = true
            });
            model.OrderStatusOptions.Add(new SelectListItem()
            {
                Value = ((int)OrderStatus.Processing).ToString(),
                Text = "Processing"
            });
            model.OrderStatusOptions.Add(new SelectListItem()
            {
                Value = ((int)OrderStatus.Pending).ToString(),
                Text = "Pending"
            });
            model.OrderStatusOptions.Add(new SelectListItem()
            {
                Value = ((int)OrderStatus.Cancelled).ToString(),
                Text = "Cancelled"
            });
            model.OrderStatusOptions.Add(new SelectListItem()
            {
                Value = ((int)OrderStatus.Complete).ToString(),
                Text = "Complete"
            });


            return View(model);
        }

        [HttpPost, GridAction(EnableCustomBinding = true)]
        public ActionResult OrderList(GridCommand command, CustomerOrderListModel orderListModel)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;

            OrderStatus? orderStatus = null;
            DateTime? startTime = null;
            DateTime? endTime = null;
            int? orderId = -1;
            if (orderListModel != null && orderListModel.OrderDayOption.HasValue)
            {
                var now = DateTime.UtcNow;
                switch (orderListModel.OrderDayOption.Value)
                {
                    case 1:
                        startTime = now.AddDays(-30);
                        endTime = now;
                        break;
                    case 2:
                        startTime = now.AddDays(-90);
                        endTime = now;
                        break;
                    case 3:
                        startTime = now.AddDays(-180);
                        endTime = now;
                        break;
                    default:
                        var newDate = now.AddMonths(orderListModel.OrderDayOption.Value);
                        startTime = new DateTime(newDate.Year, newDate.Month, 1);
                        endTime = startTime.Value.AddMonths(1).AddDays(-1);
                        break;
                }
            }
            if (orderListModel.OrderStatus.HasValue && orderListModel.OrderStatus > 0)
                orderStatus = (OrderStatus)(orderListModel.OrderStatus.Value);

            if (orderListModel.OrderId.HasValue && orderListModel.OrderId > 0)
                orderId = orderListModel.OrderId;

            var orders = _orderService.GetOrdersByCustomerId(customer.Id, 1, OrderKind.Commerce, command.Page - 1, command.PageSize, orderId.Value, startTime, endTime, orderStatus);

            var orderCommerceModels = new List<CustomerOrderListModel.OrderDetailsModel>();
            foreach (var order in orders)
            {
                var createdOn = _dateTimeHelper.ConvertToUserTime(order.CreatedOnUtc, DateTimeKind.Utc);
                var orderModel = new CustomerOrderListModel.OrderDetailsModel()
                {
                    Id = order.Id,
                    CreatedOn = createdOn,
                    CreatedOnStr = createdOn.ToString("g"),
                    OrderStatus = order.OrderStatus.GetLocalizedEnum(_localizationService, _workContext),
                    IsReturnRequestAllowed = _orderProcessingService.IsReturnRequestAllowed(order),
                    PaymentStatus = ((PaymentStatus)order.PaymentStatusId).ToString()
                };
                if (order.PaymentStatus == PaymentStatus.Pending)
                {
                    orderModel.DetailsStr = "<a href='" + Url.RouteUrl("CheckoutOnePage", new { type = "o", Id = order.Id }) + "' class='order-pending-continue btn btn-normal form-control'>View</a>";
                }
                else
                {
                    orderModel.DetailsStr = "<input type='button' class='order-details-button btn btn-normal form-control' data-id='" + order.Id + "' value='View' />";
                }

                var orderTotalInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderTotal, order.CurrencyRate);
                orderModel.OrderTotal = _priceFormatter.FormatPrice(orderTotalInCustomerCurrency, true, order.CustomerCurrencyCode, false, _workContext.WorkingLanguage);

                orderCommerceModels.Add(orderModel);
            }

            var model = new GridModel<CustomerOrderListModel.OrderDetailsModel>
            {
                Data = orderCommerceModels,
                Total = orders.TotalCount
            };

            return new JsonResult
            {
                Data = model
            };
        }

        [HttpPost, ActionName("Orders")]
        [FormValueRequired(FormValueRequirement.StartsWith, "cancelRecurringPayment")]
        public ActionResult CancelRecurringPayment(FormCollection form)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            //get recurring payment identifier
            int recurringPaymentId = 0;
            foreach (var formValue in form.AllKeys)
                if (formValue.StartsWith("cancelRecurringPayment", StringComparison.InvariantCultureIgnoreCase))
                    recurringPaymentId = Convert.ToInt32(formValue.Substring("cancelRecurringPayment".Length));

            var recurringPayment = _orderService.GetRecurringPaymentById(recurringPaymentId);
            if (recurringPayment == null)
            {
                return RedirectToRoute("CustomerOrders");
            }

            var customer = _workContext.CurrentCustomer;
            if (_orderProcessingService.CanCancelRecurringPayment(customer, recurringPayment))
            {
                var errors = _orderProcessingService.CancelRecurringPayment(recurringPayment);

                var model = PrepareCustomerOrderListModel(customer);
                model.CancelRecurringPaymentErrors = errors;

                return View(model);
            }
            else
            {
                return RedirectToRoute("CustomerOrders");
            }
        }

        #endregion

        #region Invoices

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult Invoices()
        {
            var customer = _workContext.CurrentCustomer;

            var invoices = _invoiceService.GetInvoicesByCustomerId(customer.Id);

            //if (invoices == null || invoices.Count == 0)
            //    return RedirectToRoute("CustomerInfo");

            if (invoices.Any(x => x.InvoiceStatus == InvoiceStatus.Published))
            {
                var totalDue = _invoiceService.GetTotalDueByCustomer(_workContext.CurrentCustomer);
                if (totalDue > 0)
                {
                    // invoice must not be empty here, so get the latest invoice due date.
                    var dueDate = invoices.First().DueDate;
                    if (dueDate.HasValue)
                    {
                        ViewBag.DueWarning = String.Format(
                            _localizationService.GetResource("Logistics.Order.Invoice.TotalDue"),
                            _priceFormatter.FormatPrice(totalDue),
                            dueDate.Value.ToString("MM/dd/yyyy"));
                    }
                }
            }

            var model = new CustomerInvoiceListModel()
            {
                NavigationModel = GetCustomerNavigationModel(customer)
            };
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Invoices;
            model.InvoiceDaysOptions = new List<SelectListItem>();
            model.InvoiceDaysOptions.Add(new SelectListItem()
            {
                Value = "1",
                Text = "Last 30 Days",
                Selected = true
            });
            model.InvoiceDaysOptions.Add(new SelectListItem()
            {
                Value = "2",
                Text = "Last 90 Days"
            });
            model.InvoiceDaysOptions.Add(new SelectListItem()
            {
                Value = "3",
                Text = "Last 180 Days"
            });
            var now = DateTime.UtcNow;
            for (var i = 0; i > -24; i--)
            {
                var newMonthDate = now.AddMonths(i);
                model.InvoiceDaysOptions.Add(new SelectListItem()
                {
                    Value = i.ToString(),
                    Text = newMonthDate.Year.ToString() + " " + newMonthDate.ToString("MMMM")
                });
            }
            return View(model);
        }

        [HttpPost, GridAction(EnableCustomBinding = true)]
        public ActionResult InvoicesList(GridCommand command, CustomerInvoiceListModel model)
        {
            var customer = _workContext.CurrentCustomer;
            var invoiceNumber = !String.IsNullOrEmpty(model.InvoiceNumber) ? model.InvoiceNumber : "";
            DateTime? startTime = null;
            DateTime? endTime = null;
            if (model.InvoiceDayOption.HasValue)
            {
                var now = DateTime.UtcNow;
                switch (model.InvoiceDayOption.Value)
                {
                    case 1:
                        startTime = now.AddDays(-30);
                        endTime = now;
                        break;
                    case 2:
                        startTime = now.AddDays(-90);
                        endTime = now;
                        break;
                    case 3:
                        startTime = now.AddDays(-180);
                        endTime = now;
                        break;
                    default:
                        var newDate = now.AddMonths(model.InvoiceDayOption.Value);
                        startTime = new DateTime(newDate.Year, newDate.Month, 1);
                        endTime = startTime.Value.AddMonths(1).AddDays(-1);
                        break;
                }
            }
            var invoices = _invoiceService.SearchInvoices(customer.Id, startTime, endTime, null, "", "", "", invoiceNumber, "", null, null, 1, command.Page - 1, command.PageSize);
            model = new CustomerInvoiceListModel()
            {
                NavigationModel = GetCustomerNavigationModel(customer)
            };
            var gridModel = new GridModel<CustomerInvoiceListModel.InvoiceModel>()
            {
                Data = invoices.Select(i => new CustomerInvoiceListModel.InvoiceModel()
                {
                    Id = i.Id,
                    Date = _dateTimeHelper.ConvertToUserTime(i.CreatedOnUtc).ToLongDateString(),
                    Amount = _priceFormatter.FormatPrice(i.Total),
                    InvoiceNumber = i.InvoiceNumber,
                    Status = i.InvoiceStatus.ToString(),
                    PaidDate = i.PaidDateUtc.HasValue ? _dateTimeHelper.ConvertToUserTime(i.PaidDateUtc.Value, DateTimeKind.Utc).ToLongDateString() : "",
                    DueDate = i.PaidDateUtc.HasValue ? _dateTimeHelper.ConvertToUserTime(i.PaidDateUtc.Value, DateTimeKind.Utc).ToLongDateString() : "",
                    DownloadLink = (i == null
                        || customer.Id != i.CustomerId
                        || (i.InvoiceStatus != InvoiceStatus.Published &&
                            i.InvoiceStatus != InvoiceStatus.Paid &&
                            i.InvoiceStatus != InvoiceStatus.PaidByCreditCard &&
                            i.InvoiceStatus != InvoiceStatus.PaidByCheck)) ? "" : "<a class='btn btn-normal form-control' href='" + Url.Action("DownloadInvoice", "Customer", new { id = i.Id }) + "'>" + _localizationService.GetResource("Common.Download") + "</a>"
                }).ToList(),
                Total = invoices.TotalCount
            };
            return new JsonResult
            {
                Data = gridModel
            };
        }

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult EmailPreference()
        {
            var customer = _workContext.CurrentCustomer;
            CustomerEmailPreferenceModel model = new CustomerEmailPreferenceModel();
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.LogisticsInvoicePaid = customer.IsMessageEnabled(MessageSettingFlags.LogisticsInvoicePaid);
            model.LogisticsInvoiceReady = customer.IsMessageEnabled(MessageSettingFlags.LogisticsInvoiceReady);
            model.LogisticsOrderPlaced = customer.IsMessageEnabled(MessageSettingFlags.LogisticsOrderPlaced);
            model.LogisticsDelivered = customer.IsMessageEnabled(MessageSettingFlags.LogisticsDelivered);
            model.LogisticsFailedPickup = customer.IsMessageEnabled(MessageSettingFlags.LogisticsFailedPickup);
            model.LogisticsSent = customer.IsMessageEnabled(MessageSettingFlags.LogisticsSent);
            //All Logistics

            model.CommerceOrderCancelled = customer.IsMessageEnabled(MessageSettingFlags.CommerceOrderCancelled);
            model.CommerceOrderCompleted = customer.IsMessageEnabled(MessageSettingFlags.CommerceOrderCompleted);
            model.CommerceOrderPlaced = customer.IsMessageEnabled(MessageSettingFlags.CommerceOrderPlaced);
            model.CommerceSent = customer.IsMessageEnabled(MessageSettingFlags.CommerceSent);
            model.CommerceDelivered = customer.IsMessageEnabled(MessageSettingFlags.CommerceDelivered);
            model.NewsLetterSubscription = customer.IsMessageEnabled(MessageSettingFlags.NewsLetterSubscription);
            //AllCommerce
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.EmailPreference;

            return View(model);
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult EmailPreference(CustomerEmailPreferenceModel model)
        {
            var customer = _workContext.CurrentCustomer;
            model.NavigationModel = GetCustomerNavigationModel(customer);

            customer.EnableMessage(MessageSettingFlags.LogisticsInvoicePaid, model.LogisticsInvoicePaid); //fields["EmailPreferences[LogisticsInvoicePaid]"].Contains("true")? true : false);
            customer.EnableMessage(MessageSettingFlags.LogisticsInvoiceReady, model.LogisticsInvoiceReady); //fields["EmailPreferences[LogisticsInvoiceReady]"].Contains("true") ? true : false);
            customer.EnableMessage(MessageSettingFlags.LogisticsOrderPlaced, model.LogisticsOrderPlaced);
            customer.EnableMessage(MessageSettingFlags.LogisticsDelivered, model.LogisticsDelivered);
            customer.EnableMessage(MessageSettingFlags.LogisticsFailedPickup, model.LogisticsFailedPickup);
            customer.EnableMessage(MessageSettingFlags.LogisticsSent, model.LogisticsSent);
            //All Logistics
            customer.EnableMessage(MessageSettingFlags.CommerceOrderCancelled, model.CommerceOrderCancelled);
            customer.EnableMessage(MessageSettingFlags.CommerceOrderCompleted, model.CommerceOrderCompleted);
            customer.EnableMessage(MessageSettingFlags.CommerceOrderPlaced, model.CommerceOrderPlaced);
            customer.EnableMessage(MessageSettingFlags.CommerceSent, model.CommerceSent);
            customer.EnableMessage(MessageSettingFlags.CommerceDelivered, model.CommerceDelivered);
            //All Commerce

            model.NavigationModel.SelectedTab = CustomerNavigationEnum.EmailPreference;
            _customerService.UpdateCustomer(customer);

            return View(model);
        }

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult DownloadInvoice(int id)
        {
            ModelState.Clear();
            var invoice = _invoiceService.GetInvoiceById(id);
            if (invoice == null)
            {
                ModelState.AddModelError("", "Invoice not found.");
                return Json(new
                {
                    messages = RenderMessages()
                });
            }
            if (invoice.CustomerId == _workContext.CurrentCustomer.Id)
                return PdfInvoice(invoice);

            return null;
        }

        [NonAction]
        protected ActionResult PdfInvoice(Invoice invoice)
        {
            var customer = _workContext.CurrentCustomer;
            if (invoice == null
                || customer.Id != invoice.CustomerId
                || (invoice.InvoiceStatus != InvoiceStatus.Published &&
                    invoice.InvoiceStatus != InvoiceStatus.Paid &&
                    invoice.InvoiceStatus != InvoiceStatus.PaidByCreditCard &&
                    invoice.InvoiceStatus != InvoiceStatus.PaidByCheck)
                )
            {
                _customerActivityService.InsertActivity(
                    "Invoice.Download",
                    _localizationService.GetResource("ActivityLog.Invoice.DownloadInvalid"),
                    customer, invoice == null ? 0 : invoice.Id);
                ModelState.Clear();
                ModelState.AddModelError("", _localizationService.GetResource("ActivityLog.Invoice.DownloadInvalid"));
                AddModelStateErrorMessages();
                return RedirectToAction("Invoices", "Customer");
            }

            byte[] bytes = null;
            using (var stream = new System.IO.MemoryStream())
            {
                _pdfService.PrintInvoiceToPdf(stream, invoice, _workContext.WorkingLanguage);
                bytes = stream.ToArray();
            }
            return File(bytes, "application/pdf", String.Format("invoice_{0}.pdf", invoice.InvoiceNumber));
        }

        #endregion

        #region Payment
#if false
        [NopHttpsRequirement(SslRequirement.Yes)]
        [MobileRedirect]
        public ActionResult PaymentInfo()
        {
            var customer = _workContext.CurrentCustomer;
            //validation
            var cart = customer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.Logistics).ToList();
            if (cart.Count != 1)
            {
                ClearShoppingCart();
                _authenticationService.SignOut();
                _customerService.DeleteCustomer(customer);
                return RedirectToAction("Register");
            }

            //model
            var model = new SummaryModel();
            var pv = cart.Single().ProductVariant;
            model.Address = PrepareAddressModel(_workContext.CurrentCustomer.ShippingAddress);
            model.Subtotal = pv.Price;
            model.Tax = model.Subtotal * _logisticsInformationSettings.TaxRate;
            var total = model.Subtotal + model.Tax;
            model.Total = model.Subtotal + model.Tax;

            model.BillingAddress = PrepareAddressModel(customer.BillingAddress);
            model.MembershipInfo = string.Format("{0} ({1})", pv.Product.Name, pv.Name);

            var processPaymentRequest = new ProcessPaymentRequest()
            {
                OrderTotal = total
            };
            _httpContext.Session[PaymentContants.PaymentInfoSessionKey] = processPaymentRequest;
            SavePaymentInformation(total, customer);
            return View(model);
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult PaymentInfo(FormCollection form)
        {
            var customer = _workContext.CurrentCustomer;
            //validation
            var cart = customer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.Logistics).ToList();
            if (cart.Count != 1)
            {
                ClearShoppingCart();
                _authenticationService.SignOut();
                _customerService.DeleteCustomer(customer);
                return RedirectToAction("Register");
            }

            try
            {
                if (ModelState.IsValid)
                {
                    if (form["succeeded"] == "succeeded")
                    {
                        RemovePaymentInformation(customer);
                        PlaceOrder(customer);

                        PromoteCustomer(customer);
                        ExtendMembership(customer);

                        return RedirectToAction("PaymentConfirm");
                    }
                }

                //If we got this far, something failed, redisplay form
                //model
                var model = new SummaryModel();
                var pv = customer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.Logistics)
                    .Single().ProductVariant;
                model.Address = PrepareAddressModel(_workContext.CurrentCustomer.ShippingAddress);
                model.Subtotal = pv.Price;
                model.Tax = model.Subtotal * _logisticsInformationSettings.TaxRate;
                var total = model.Subtotal + model.Tax;
                model.Total = model.Subtotal + model.Tax;
                model.MembershipInfo = string.Format("{0} ({1})", pv.Product.Name, pv.Name);
                var processPaymentRequest = new ProcessPaymentRequest()
                {
                    OrderTotal = total
                };
                _httpContext.Session[PaymentContants.PaymentInfoSessionKey] = processPaymentRequest;
                SavePaymentInformation(total, customer);
                return View(model);
            }
            catch (Exception e)
            {
                return FatalErrorView(e.Message, customer, e);
            }
        }

        private AddressModel PrepareAddressModel(Address address)
        {
            var model = new AddressModel();
            model.CompanyEnabled = true;
            model.Company = address.Company;
            model.FirstName = address.FirstName;
            model.LastName = address.LastName;
            model.StreetAddressEnabled = true;
            model.StreetAddressRequired = true;
            model.Address1 = address.Address1;
            model.StreetAddress2Enabled = true;
            model.Address2 = address.Address2;
            model.CityEnabled = true;
            model.City = address.City;

            //TODO: remove hard code for province
            model.StateProvinceEnabled = true;
            model.StateProvinceName = address.StateProvince.Name;
            model.StateProvinceId = address.StateProvinceId;
            model.ZipPostalCodeEnabled = true;
            model.ZipPostalCode = address.ZipPostalCode;

            //TODO: remove hard code for country
            model.CountryEnabled = true;
            model.CountryName = address.Country.Name;
            model.CountryId = address.CountryId;
            model.Email = address.Email;
            model.CellPhoneEnabled = true;
            model.CellPhoneNumber = address.CellPhoneNumber;
            model.PhoneEnabled = true;
            model.PhoneNumber = address.PhoneNumber;
            return model;
        }

        private void SavePaymentInformation(decimal total, Customer customer)
        {
            _genericAttributeService.SaveAttribute<string>(customer, SystemCustomerAttributeNames.LogisticsPaymentInformaiton, total.ToString());
        }

        private void RemovePaymentInformation(Customer customer)
        {
            _genericAttributeService.SaveAttribute<string>(customer, SystemCustomerAttributeNames.LogisticsPaymentInformaiton, null);
        }
#endif
        #endregion

        #region Addresses

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult Addresses()
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;

            var model = new CustomerAddressListModel();
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Addresses;
            model.ShippingAddressId = _workContext.CurrentCustomer.ShippingAddress != null ? _workContext.CurrentCustomer.ShippingAddress.Id : 0;
            model.BillingAddressId = _workContext.CurrentCustomer.BillingAddress != null ? _workContext.CurrentCustomer.BillingAddress.Id : 0;
            foreach (var address in customer.Addresses)
            {
                var addressModel = new SpotsHub.Gateway.Models.Common.AddressModel();
                addressModel.PrepareModel(address, false, _addressSettings, _localizationService,
                    _stateProvinceService, () => _countryService.GetAllCountries());
                model.Addresses.Add(addressModel);
            }
            var countries = _countryService.GetAllCountries();
            foreach (var c in countries)
            {
                var l = new SelectListItem()
                {
                    Value = c.Id.ToString(),
                    Text = c.Name
                };
                model.AvailableCountries.Add(l);
            }
            var stateProvinces = _stateProvinceService.GetStateProvincesByCountryId(countries.Count < 1 ? 1 : countries.First(c => c.TwoLetterIsoCode == "CA").Id);
            foreach (var sp in stateProvinces)
            {
                var li = new SelectListItem()
                {
                    Value = sp.Id.ToString(),
                    Text = sp.Name
                };
                model.AvailableStates.Add(li);
            }
            return PartialView(model);
        }

        [HttpPost, GridAction(EnableCustomBinding = true)]
        public ActionResult AddressesLoad(GridCommand command)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;
            IList<SpotsHub.Gateway.Models.Common.AddressModel> addresses = new CustomerAddressListModel().Addresses;
            var pagedAddresses = customer.Addresses;
            if (command.PageSize > 0)
            {
                pagedAddresses = customer.Addresses.Skip((command.Page - 1) * command.PageSize).ToList();
            }
            foreach (var address in pagedAddresses)
            {
                var model = new SpotsHub.Gateway.Models.Common.AddressModel();
                model.PrepareModel(address, false, _addressSettings, _localizationService,
                    _stateProvinceService, () => _countryService.GetAllCountries());

                //var addressHtmlSb = new StringBuilder("<div>");
                //if (_addressSettings.StreetAddressEnabled && !String.IsNullOrEmpty(model.Address1))
                //    addressHtmlSb.AppendFormat("{0}<br />", Server.HtmlEncode(model.Address1));
                //if (_addressSettings.StreetAddress2Enabled && !String.IsNullOrEmpty(model.Address2))
                //    addressHtmlSb.AppendFormat("{0}<br />", Server.HtmlEncode(model.Address2));
                //if (_addressSettings.CityEnabled && !String.IsNullOrEmpty(model.City))
                //    addressHtmlSb.AppendFormat("{0},", Server.HtmlEncode(model.City));
                //if (_addressSettings.StateProvinceEnabled && !String.IsNullOrEmpty(model.StateProvinceName))
                //    addressHtmlSb.AppendFormat("{0},", Server.HtmlEncode(model.StateProvinceName));
                //if (_addressSettings.ZipPostalCodeEnabled && !String.IsNullOrEmpty(model.ZipPostalCode))
                //    addressHtmlSb.AppendFormat("{0}<br />", Server.HtmlEncode(model.ZipPostalCode));
                //if (_addressSettings.CountryEnabled && !String.IsNullOrEmpty(model.CountryName))
                //    addressHtmlSb.AppendFormat("{0}", Server.HtmlEncode(model.CountryName));
                //addressHtmlSb.Append("</div>");
                model.AddressHtml = address.FormattedAddress();
                model.IsBillingAddress = customer.BillingAddress != null && customer.BillingAddress.Id == model.Id;
                model.IsShippingAddress = customer.ShippingAddress != null && customer.ShippingAddress.Id == model.Id;
                addresses.Add(model);
            }
            var gridModel = new GridModel<SpotsHub.Gateway.Models.Common.AddressModel>
            {
                Data = addresses,
                Total = customer.Addresses.Count
            };
            return new JsonResult
            {
                Data = gridModel
            };
        }

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult AddressDelete(int addressId)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;

            //find address (ensure that it belongs to the current customer)
            var address = customer.Addresses.Where(a => a.Id == addressId).FirstOrDefault();
            if (address != null)
            {
                customer.RemoveAddress(address);
                _customerService.UpdateCustomer(customer);
                //now delete the address record
                //_addressService.DeleteAddress(address);
            }

            return RedirectToRoute("CustomerAddresses");
        }

        [HttpPost]
        public ActionResult AddressDeleteInPage(CustomerAddressEditModel model)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            ModelState.Clear();
            var customer = _workContext.CurrentCustomer;
            var addressId = model.Address.Id;
            //find address (ensure that it belongs to the current customer)
            var address = customer.Addresses.Where(a => a.Id == addressId).FirstOrDefault();
            var success = false;
            var notices = new List<string>();
            if (address != null)
            {
                if (customer.ShippingAddress != null && address.Id == customer.ShippingAddress.Id)
                {
                    customer.ShippingAddress = null;
                    notices.Add("The default shipping address is removed.");
                }
                if (customer.BillingAddress != null && address.Id == customer.BillingAddress.Id)
                {
                    customer.BillingAddress = null;
                    notices.Add("The default billing address is removed.");
                }
                customer.RemoveAddress(address);
                _customerService.UpdateCustomer(customer);
                notices.Add("Successfully removed this address.");
                success = true;
                //we cannot delete record in database
                //_addressService.DeleteAddress(address);
            }
            else
            {
                ModelState.AddModelError("", "Unable to delete this address.");
            }
            return Json(new
            {
                success = success,
                messages = RenderMessages(notices)
            });

        }

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult AddressAdd()
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;

            var model = new CustomerAddressEditModel();
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Addresses;
            model.Address.PrepareModel(null, false, _addressSettings, _localizationService,
                    _stateProvinceService, () => _countryService.GetAllCountries());

            return View(model);
        }

        [NopHttpsRequirement(SslRequirement.Yes)]
        [ChildActionOnly]
        public ActionResult AddressAddInPage()
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;

            var model = new CustomerAddressEditModel();
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Addresses;
            model.Address.PrepareModel(null, false, _addressSettings, _localizationService,
                    _stateProvinceService, () => _countryService.GetAllCountries());
            if (model.Address.CountryId == 0 || model.Address.CountryId == null || model.Address.CountryName == null)
            {
                var countries = _countryService.GetAllCountries();
                var stateProvinces = _stateProvinceService.GetStateProvincesByCountryId(countries.Count < 1 ? 1 : countries.First(c => c.TwoLetterIsoCode == "CA").Id);
                Country country = countries.First(c => c.TwoLetterIsoCode == "CA");
                model.Address.CountryId = country.Id;
                model.Address.CountryName = country.Name;
                model.Address.AvailableStates.Clear();
                foreach (var sp in stateProvinces)
                {
                    model.Address.AvailableStates.Add(new SelectListItem
                    {
                        Text = sp.Name,
                        Value = sp.Id.ToString()
                    });
                }
            }
            return PartialView(model);
        }

        [HttpPost]
        public ActionResult AddressAdd(CustomerAddressEditModel model)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;


            if (ModelState.IsValid)
            {
                var address = model.Address.ToEntity();
                address.CreatedOnUtc = DateTime.UtcNow;
                //some validation
                if (address.CountryId == 0)
                    address.CountryId = null;
                if (address.StateProvinceId == 0)
                    address.StateProvinceId = null;
                customer.Addresses.Add(address);
                _customerService.UpdateCustomer(customer);

                return RedirectToRoute("CustomerAddresses");
            }

            //If we got this far, something failed, redisplay form
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Addresses;
            model.Address.PrepareModel(null, true, _addressSettings, _localizationService,
                    _stateProvinceService, () => _countryService.GetAllCountries());

            return View(model);
        }

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult AddressEdit(int addressId)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;
            //find address (ensure that it belongs to the current customer)
            var address = customer.Addresses.Where(a => a.Id == addressId).FirstOrDefault();
            if (address == null)
                //address is not found
                return RedirectToRoute("CustomerAddresses");

            var model = new CustomerAddressEditModel();
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Addresses;
            model.Address.PrepareModel(address, false, _addressSettings, _localizationService,
                    _stateProvinceService, () => _countryService.GetAllCountries());

            return View(model);
        }

        [HttpPost]
        public ActionResult AddressEdit(CustomerAddressEditModel model, int addressId)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;
            //find address (ensure that it belongs to the current customer)
            var address = customer.Addresses.Where(a => a.Id == addressId).FirstOrDefault();
            if (address == null)
                //address is not found
                return RedirectToRoute("CustomerAddresses");

            if (ModelState.IsValid)
            {
                address = model.Address.ToEntity(address);
                _addressService.UpdateAddress(address);

                return RedirectToRoute("CustomerAddresses");
            }

            //If we got this far, something failed, redisplay form
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Addresses;
            model.Address.PrepareModel(address, true, _addressSettings, _localizationService,
                    _stateProvinceService, () => _countryService.GetAllCountries());
            return View(model);
        }

        [HttpPost]
        public ActionResult AddressEditInPage(CustomerAddressEditModel model, bool isShippingAddress = false, bool isBillingAddress = false, bool isDelete = false)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            if (isDelete)
            {
                return AddressDeleteInPage(model);
            }

            var customer = _workContext.CurrentCustomer;
            var address = model.Address.ToEntity();
            var addaddress = false;
            var notices = new List<string>();
            model.IsShippingAddress = false;
            model.IsBillingAddress = false;

            if (model.Address.Id != 0)
            {
                //find address (ensure that it belongs to the current customer)
                address = customer.Addresses.Where(a => a.Id == model.Address.Id).FirstOrDefault();
                if (address == null)
                    //address is not found
                    return RedirectToRoute("CustomerAddresses");
            }
            else //create address
            {
                addaddress = true;
                address.CreatedOnUtc = DateTime.UtcNow;
            }

            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Addresses;
            model.Address.PrepareModel(address, true, _addressSettings, _localizationService,
                    _stateProvinceService, () => _countryService.GetAllCountries());

            var success = false;

            if (ModelState.IsValid)
            {
                if (model.Address.Id != 0)
                {
                    address = model.Address.ToEntity(address);
                    if (address.Type == null)
                    {
                        address.Type = AddressType.Business;
                    }
                    _addressService.UpdateAddress(address);
                    notices.Add("The address has been updated.");
                    if (isShippingAddress)
                    {
                        if (customer.ShippingAddress == null || (customer.ShippingAddress != null && customer.ShippingAddress.Id != address.Id))
                        {
                            notices.Add("A new default shipping address is saved.");
                        }
                        customer.ShippingAddress = address;
                    }
                    else
                    {
                        if (customer.ShippingAddress != null && customer.ShippingAddress.Id == address.Id)
                        {
                            customer.ShippingAddress = null;
                            notices.Add("The default shipping address is removed.");
                        }
                    }
                    if (isBillingAddress)
                    {
                        if (customer.BillingAddress == null || (customer.BillingAddress != null && customer.BillingAddress.Id != address.Id))
                        {
                            notices.Add("A new default billing address is saved.");
                        }
                        customer.BillingAddress = address;
                    }
                    else
                    {
                        if (customer.BillingAddress != null && customer.BillingAddress.Id == address.Id)
                        {
                            customer.BillingAddress = null;
                            notices.Add("The default billing address is removed.");
                        }
                    }
                    _customerService.UpdateCustomer(customer);
                }
                else
                {
                    //some validation
                    if (address.CountryId == 0)
                        address.CountryId = null;
                    if (address.StateProvinceId == 0)
                        address.StateProvinceId = null;
                    //set default address type
                    address.Type = AddressType.Business;
                    customer.Addresses.Add(address);

                    notices.Add("A new address has been saved.");
                    if (isShippingAddress)
                    {
                        customer.ShippingAddress = address;
                        notices.Add("A new default shipping address is saved.");
                    }
                    if (isBillingAddress)
                    {
                        customer.BillingAddress = address;
                        notices.Add("A new default billing address is saved.");
                    }
                    _customerService.UpdateCustomer(customer);

                    //get the newly added address
                    customer = _workContext.CurrentCustomer;
                    customer.Addresses.OrderBy(x => x.CreatedOnUtc);
                    model.Address.Id = customer.Addresses.Last().Id;

                }
                success = true;

            }
            else
            {
                if (model.Address.CountryId == 0 || model.Address.CountryId == null || model.Address.CountryName == null)
                {
                    var countries = _countryService.GetAllCountries();
                    var stateProvinces = _stateProvinceService.GetStateProvincesByCountryId(countries.Count < 1 ? 1 : countries.First(c => c.TwoLetterIsoCode == "CA").Id);
                    Country country = countries.First(c => c.TwoLetterIsoCode == "CA");
                    model.Address.CountryId = country.Id;
                    model.Address.CountryName = country.Name;
                    model.Address.AvailableStates.Clear();
                    foreach (var sp in stateProvinces)
                    {
                        model.Address.AvailableStates.Add(new SelectListItem
                        {
                            Text = sp.Name,
                            Value = sp.Id.ToString()
                        });
                    }
                }
            }
            if (customer.ShippingAddress != null && customer.ShippingAddress.Id == model.Address.Id)
            {
                model.IsShippingAddress = true;
            }
            if (customer.BillingAddress != null && customer.BillingAddress.Id == model.Address.Id)
            {
                model.IsBillingAddress = true;
            }
            var defaultShippingAddressId = 0;
            var defaultBillingAddressId = 0;
            if (customer.ShippingAddress != null)
            {
                defaultShippingAddressId = customer.ShippingAddress.Id;
            }
            if (customer.BillingAddress != null)
            {
                defaultBillingAddressId = customer.BillingAddress.Id;
            }
            var rendered = this.RenderPartialViewToString("AddressEditInPage", model);

            //If we got this far, something failed, redisplay form
            return Json(new
            {
                addaddress = addaddress,
                success = success,
                id = model.Address.Id,
                html = rendered,
                messages = RenderMessages(notices)
            });
        }

        [HttpPost]
        public ActionResult AddressSetDefault(string type, int addressId)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;
            bool success = false;
            //find address (ensure that it belongs to the current customer)
            var address = customer.Addresses.Where(a => a.Id == addressId).FirstOrDefault();
            if (address != null)
            {
                if (type == "Shipping")
                {
                    customer.ShippingAddress = address;
                }
                else
                {
                    customer.BillingAddress = address;
                }
                _customerService.UpdateCustomer(customer);
                success = true;
            }
            return Json(new
            {
                success = success,
                id = addressId
            });
        }

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult AddressEditChange(int addressId, int shipmentId, string addressType)
        {
            var customer = _workContext.CurrentCustomer;
            if (!customer.IsRegistered())
                return new HttpUnauthorizedResult();

            if (customer.GetAttribute<decimal?>(SystemCustomerAttributeNames.LogisticsPaymentInformaiton) > 0M)
                return RedirectToAction("PaymentInfo", new { returnUrl = Url.Action("AddressEditChange", new { addressId = addressId, shipmentId = shipmentId, addressType = addressType }) });

            //find address (ensure that it belongs to the current customer)
            var address = customer.Addresses.Where(a => a.Id == addressId).FirstOrDefault();
            if (address == null)
                //address is not found
                return RedirectToRoute("CustomerAddresses");

            var model = new CustomerAddressEditModel();

            var addressList = customer.Addresses
                .Select(a => new SelectListItem() { Selected = false, Text = a.FormattedAddress(), Value = a.Id.ToString() })
                .ToList();
            addressList.Insert(0, new SelectListItem() { Selected = true, Text = "Add a new address", Value = "0" });
            model.CustomProperties.Add("addresslist", addressList);
            model.AddressType = addressType;

            model.ShipmentId = shipmentId;

            model.Address.PrepareModel(address, false, _addressSettings, _localizationService,
                    _stateProvinceService, () => _countryService.GetAllCountries());

            return View(model);
        }

        public ActionResult AddressSelect(int addressId)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;
            //find address (ensure that it belongs to the current customer)
            var model = new CustomerAddressEditModel();

            var address = customer.Addresses.Where(a => a.Id == addressId).FirstOrDefault();
            if (address == null)
                //address is not found
                //return RedirectToRoute("CustomerAddresses");
                return Json(new { Success = false, objModel = model }, JsonRequestBehavior.AllowGet);

            var addressList =
                customer.Addresses.Select(a => new SelectListItem() { Selected = false, Text = a.FormattedAddress(), Value = a.Id.ToString() })
                .ToList();
            addressList.Insert(0, new SelectListItem() { Selected = true, Text = "Add a new address", Value = "0" });
            model.CustomProperties.Add("addresslist", addressList);

            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Addresses;
            model.Address.PrepareModel(address, false, _addressSettings, _localizationService,
                    _stateProvinceService, () => _countryService.GetAllCountries());

            return Json(new { Success = true, objModel = model }, JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        public ActionResult AddressEditChange(CustomerAddressEditModel model, int addressId)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            if (ModelState.IsValid)
            {
                try
                {
                    var pkg = _logisticsService.GetPackageByShipmentId(model.ShipmentId);
                    var customer = _workContext.CurrentCustomer;
                    var address = _workContext.CurrentCustomer.Addresses.ToList().FindAddress(model.Address.FirstName,
                        model.Address.LastName, model.Address.PhoneNumber, model.Address.CellPhoneNumber, model.Address.Email,
                        model.Address.FaxNumber, model.Address.Company, model.Address.Address1, model.Address.Address2,
                       model.Address.City, model.Address.StateProvinceId, model.Address.ZipPostalCode, model.Address.CountryId);

                    if (address == null)
                    {
                        address = new Address()
                        {
                            FirstName = model.Address.FirstName,
                            LastName = model.Address.LastName,
                            PhoneNumber = model.Address.PhoneNumber,
                            CellPhoneNumber = model.Address.CellPhoneNumber,
                            Email = model.Address.Email,
                            FaxNumber = model.Address.FaxNumber,
                            Company = model.Address.Company,
                            Address1 = model.Address.Address1,
                            Address2 = model.Address.Address2,
                            City = model.Address.City,
                            StateProvinceId = model.Address.StateProvinceId,
                            ZipPostalCode = model.Address.ZipPostalCode,
                            CountryId = model.Address.CountryId

                        };
                        customer.Addresses.Add(address);
                        _customerService.UpdateCustomer(customer);
                    }

                    if (model.AddressType == "PickupAddress")
                        if (!_logisticsProcessingService.ChangePackagePickupAddress(pkg, model.Address.Id))
                            ErrorNotification("Changing pickup address address has failed.");

                    if (model.AddressType == "DeliveryAddress")
                        if (!_logisticsProcessingService.ChangePackageDeliveryAddress(pkg, model.Address.Id))
                            ErrorNotification("Changing delivery address address has failed.");
                }
                catch (Exception exc)
                {
                    ErrorNotification(exc, true);
                }
                return RedirectToAction("Tracking");
            }

            return View(model);
        }

        public ActionResult PaymentInfo(string returnUrl)
        {
            var customer = _workContext.CurrentCustomer;

            if (customer.BillingAddress == null)
            {
                //TODO: Add the error message
                return RedirectToAction("Addresses");
            }

            return View(returnUrl);
        }

        [HttpPost]
        public ActionResult PaymentInfo(string returnUrl, string succeeded)
        {
            var customer = _workContext.CurrentCustomer;
            try
            {
                if (ModelState.IsValid)
                {
                    if (succeeded == "succeeded")
                    {
                        _orderlogisticsProcessingService.RemovePaymentInformation(customer);

                        if (String.IsNullOrEmpty(returnUrl))
                            return RedirectToAction("Info");

                        return Redirect(returnUrl);
                    }
                }
            }
            catch (Exception)
            {

            }
            return View(returnUrl);
        }

        #endregion

        #region Return request

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult ReturnRequests(bool? showResult)
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;
            var model = new CustomerReturnRequestsModel();
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.ReturnRequests;

            if (showResult.HasValue && showResult.Value)
            {
                model.Result = _localizationService.GetResource("ReturnRequests.Submitted");
            }

            return View(model);
        }

        [HttpPost, GridAction(EnableCustomBinding = true)]
        public ActionResult ReturnRequestsList(GridCommand command, CustomerReturnRequestsModel model)
        {
            var customer = _workContext.CurrentCustomer;
            model = new CustomerReturnRequestsModel();
            var returnRequests = _orderService.SearchReturnRequests(customer.Id, 0, null, command.Page - 1, command.PageSize);
            foreach (var returnRequest in returnRequests)
            {
                var opv = _orderService.GetOrderProductVariantById(returnRequest.OrderProductVariantId);
                if (opv != null)
                {
                    var pv = opv.ProductVariant;

                    var itemModel = new CustomerReturnRequestsModel.ReturnRequestModel()
                    {
                        Id = returnRequest.Id,
                        ReturnRequestStatus = returnRequest.ReturnRequestStatus.GetLocalizedEnum(_localizationService, _workContext),
                        ProductId = pv.ProductId,
                        ProductSeName = pv.Product.GetSeName(),
                        Quantity = returnRequest.Quantity,
                        ReturnAction = returnRequest.RequestedAction,
                        ReturnReason = returnRequest.ReasonForReturn,
                        Comments = returnRequest.CustomerComments,
                        CreatedOn = _dateTimeHelper.ConvertToUserTime(returnRequest.CreatedOnUtc, DateTimeKind.Utc),
                    };
                    model.Items.Add(itemModel);

                    if (!String.IsNullOrEmpty(pv.GetLocalized(x => x.Name)))
                        itemModel.ProductName = string.Format("{0} ({1})", pv.Product.GetLocalized(x => x.Name), pv.GetLocalized(x => x.Name));
                    else
                        itemModel.ProductName = pv.Product.GetLocalized(x => x.Name);
                }
            }
            var gridModel = new GridModel<CustomerReturnRequestsModel.ReturnRequestModel>
            {
                Data = model.Items,
                Total = returnRequests.TotalCount
            };
            return new JsonResult
            {
                Data = gridModel
            };
        }

        #endregion

        #region Settings

        public ActionResult Settings()
        {
            var model = PrepareCustomerSettingsModel();
            return View(model);
        }

        [HttpPost]
        public ActionResult Settings(CustomerSettingsModel model)
        {
            var customer = _workContext.CurrentCustomer;
            model.NavigationModel = GetCustomerNavigationModel(customer);
            var settingsType = model.SettingsType;
            if (settingsType == (int)CustomerSettingsType.EmailPreferences)
            {
                // Save email preferences
                customer.EnableMessage(MessageSettingFlags.LogisticsInvoicePaid, model.EmailPreferences.LogisticsInvoicePaid); //fields["EmailPreferences[LogisticsInvoicePaid]"].Contains("true")? true : false);
                customer.EnableMessage(MessageSettingFlags.LogisticsInvoiceReady, model.EmailPreferences.LogisticsInvoiceReady); //fields["EmailPreferences[LogisticsInvoiceReady]"].Contains("true") ? true : false);
                customer.EnableMessage(MessageSettingFlags.LogisticsOrderPlaced, model.EmailPreferences.LogisticsOrderPlaced);
                customer.EnableMessage(MessageSettingFlags.LogisticsDelivered, model.EmailPreferences.LogisticsDelivered);
                customer.EnableMessage(MessageSettingFlags.LogisticsFailedPickup, model.EmailPreferences.LogisticsFailedPickup);
                customer.EnableMessage(MessageSettingFlags.LogisticsSent, model.EmailPreferences.LogisticsSent);
                //All Logistics
                customer.EnableMessage(MessageSettingFlags.CommerceOrderCancelled, model.EmailPreferences.CommerceOrderCancelled);
                customer.EnableMessage(MessageSettingFlags.CommerceOrderCompleted, model.EmailPreferences.CommerceOrderCompleted);
                customer.EnableMessage(MessageSettingFlags.CommerceOrderPlaced, model.EmailPreferences.CommerceOrderPlaced);
                customer.EnableMessage(MessageSettingFlags.CommerceSent, model.EmailPreferences.CommerceSent);
                customer.EnableMessage(MessageSettingFlags.CommerceDelivered, model.EmailPreferences.CommerceDelivered);
                //All Commerce
                customer.EnableMessage(MessageSettingFlags.NewsLetterSubscription, model.EmailPreferences.NewsLetterSubscription);
            }
            if (settingsType == (int)CustomerSettingsType.RegionAndLanguages)
            {
                // Save region/language preferences
                customer.LanguageId = model.SelectedLanguage;
                customer.Region = _regionService.GetRegionById(model.SelectedRegion);
                customer.TimeZoneId = model.SelectedTimeZone;
            }

            if (!ModelState.IsValid)
            {
                AddModelStateErrorMessages();
            }
            else
            {
                AddSuccessMessage("Your account settings are saved.");
            }

            _customerService.UpdateCustomer(customer);
            model = PrepareCustomerSettingsModel();
            model.SettingsType = settingsType;
            return View(model);
        }

        #endregion

        # region Downloadables

        [NopHttpsRequirement(SslRequirement.Yes)]
        public ActionResult DownloadableProducts()
        {
            if (!IsCurrentUserRegistered())
                return new HttpUnauthorizedResult();

            var customer = _workContext.CurrentCustomer;

            var model = new CustomerDownloadableProductsModel();
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.DownloadableProducts;
            var items = _orderService.GetAllOrderProductVariants(null, customer.Id, null, null,
                null, null, null, true);
            foreach (var item in items)
            {
                var itemModel = new CustomerDownloadableProductsModel.DownloadableProductsModel()
                {
                    OrderProductVariantGuid = item.OrderProductVariantGuid,
                    OrderId = item.OrderId,
                    CreatedOn = _dateTimeHelper.ConvertToUserTime(item.Order.CreatedOnUtc, DateTimeKind.Utc),
                    ProductSeName = item.ProductVariant.Product.GetSeName(),
                    ProductAttributes = item.AttributeDescription,
                    ProductId = item.ProductVariant.ProductId
                };
                model.Items.Add(itemModel);

                //product name
                if (!String.IsNullOrEmpty(item.ProductVariant.GetLocalized(x => x.Name)))
                    itemModel.ProductName = string.Format("{0} ({1})", item.ProductVariant.Product.GetLocalized(x => x.Name), item.ProductVariant.GetLocalized(x => x.Name));
                else
                    itemModel.ProductName = item.ProductVariant.Product.GetLocalized(x => x.Name);

                if (_downloadService.IsDownloadAllowed(item))
                    itemModel.DownloadId = item.ProductVariant.DownloadId;

                if (_downloadService.IsLicenseDownloadAllowed(item))
                    itemModel.LicenseId = item.LicenseDownloadId.HasValue ? item.LicenseDownloadId.Value : 0;
            }

            return View(model);
        }

        public ActionResult UserAgreement(Guid opvId)
        {
            var opv = _orderService.GetOrderProductVariantByGuid(opvId);
            if (opv == null)
                return RedirectToRoute("HomePage");


            var productVariant = opv.ProductVariant;
            if (productVariant == null || !productVariant.HasUserAgreement)
                return RedirectToRoute("HomePage");

            var model = new UserAgreementModel();
            model.UserAgreementText = productVariant.UserAgreementText;
            model.OrderProductVariantGuid = opvId;

            return View(model);
        }

        #endregion

        #region Back in stock subscriptions

        public ActionResult BackInStockSubscriptions(int? page)
        {
            if (_customerSettings.HideBackInStockSubscriptionsTab)
            {
                return RedirectToRoute("CustomerInfo");
            }

            int pageIndex = 0;
            if (page > 0)
            {
                pageIndex = page.Value - 1;
            }

            var customer = _workContext.CurrentCustomer;
            var pageSize = 10;
            var list = _backInStockSubscriptionService.GetAllSubscriptionsByCustomerId(customer.Id, pageIndex, pageSize);

            var model = new CustomerBackInStockSubscriptionsModel();
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.BackInStockSubscriptions;

            foreach (var subscription in list)
            {
                var productVariant = subscription.ProductVariant;

                if (productVariant != null)
                {
                    var subscriptionModel = new BackInStockSubscriptionModel()
                    {
                        Id = subscription.Id,
                        ProductId = productVariant.Product.Id,
                        SeName = productVariant.Product.GetSeName(),
                    };
                    //product name
                    if (!String.IsNullOrEmpty(productVariant.GetLocalized(x => x.Name)))
                        subscriptionModel.ProductName = string.Format("{0} ({1})",
                                                                      productVariant.Product.GetLocalized(x => x.Name),
                                                                      productVariant.GetLocalized(x => x.Name));
                    else
                        subscriptionModel.ProductName = productVariant.Product.GetLocalized(x => x.Name);

                    model.Subscriptions.Add(subscriptionModel);
                }
            }

            model.PagerModel = new SpotsHub.Gateway.Models.Common.PagerModel()
            {
                PageSize = list.PageSize,
                TotalRecords = list.TotalCount,
                PageIndex = list.PageIndex,
                ShowTotalSummary = false,
                RouteActionName = "CustomerBackInStockSubscriptionsPaged",
                UseRouteLinks = true,
                RouteValues = new SpotsHub.Gateway.Models.Common.BackInStockSubscriptionsRouteValues { page = pageIndex }
            };

            return View(model);
        }

        [HttpPost, ActionName("BackInStockSubscriptions")]
        public ActionResult BackInStockSubscriptionsPOST(FormCollection formCollection)
        {
            foreach (var key in formCollection.AllKeys)
            {
                var value = formCollection[key];

                if (value.Equals("on") && key.StartsWith("biss", StringComparison.InvariantCultureIgnoreCase))
                {
                    var id = key.Replace("biss", "").Trim();
                    int subscriptionId = 0;

                    if (Int32.TryParse(id, out subscriptionId))
                    {
                        var subscription = _backInStockSubscriptionService.GetSubscriptionById(subscriptionId);
                        if (subscription != null && subscription.CustomerId == _workContext.CurrentCustomer.Id)
                        {
                            _backInStockSubscriptionService.DeleteSubscription(subscription);
                        }
                    }
                }
            }

            return RedirectToRoute("CustomerBackInStockSubscriptions");
        }

        public ActionResult DeleteBackInStockSubscription(int subscriptionId)
        {
            var subscription = _backInStockSubscriptionService.GetSubscriptionById(subscriptionId);
            if (subscription != null && subscription.CustomerId == _workContext.CurrentCustomer.Id)
            {
                _backInStockSubscriptionService.DeleteSubscription(subscription);
            }

            return RedirectToRoute("CustomerBackInStockSubscriptions");
        }

        #endregion



        #endregion

        #region Utilities

        [NonAction]
        private DateTime GetEndDate(DateTime? endDate, ClubMembership membership)
        {
            TimeSpan timeSpan = TimeSpan.MinValue;
            timeSpan = new TimeSpan(membership.MembershipDuration, 0, 0, 0);

            if (timeSpan > TimeSpan.MinValue)
            {
                if (endDate.HasValue && endDate.Value > DateTime.UtcNow)
                {
                    return endDate.Value.Add(timeSpan);
                }
                else
                    return DateTime.UtcNow.Add(timeSpan);
            }

            throw new ArgumentException("Invalid Membership Product");
        }

        [NonAction]
        protected int GetStoreId()
        {
            return Nop.Core.Domain.Stores.Store.AllStoreReservedId;
            //int? storeId = _httpContext.Session["StoreId"] as int?;

            //if (!storeId.HasValue)
            //{
            //    throw new NopException("The store ID is unknown.");
            //}
            //return storeId.Value;
        }

        [NonAction]
        protected bool IsCurrentUserRegistered()
        {
            return _workContext.CurrentCustomer.IsRegistered();
        }

        [NonAction]
        protected void AddSuccessMessage(string msg)
        {
            if (TempData["successes"] == null)
                TempData["successes"] = "";
            if (!String.IsNullOrEmpty(msg))
                TempData["successes"] += "<li>" + msg + "</li>";
        }
        [NonAction]
        protected void AddNoticeMessage(string msg)
        {
            if (TempData["notices"] == null)
                TempData["notices"] = "";
            if (!String.IsNullOrEmpty(msg))
                TempData["notices"] += "<li>" + msg + "</li>";
        }
        [NonAction]
        protected void AddErrorMessage(string msg)
        {
            if (TempData["errors"] == null)
                TempData["errors"] = "";
            if (!String.IsNullOrEmpty(msg))
                TempData["errors"] += "<li>" + msg + "</li>";
        }
        [NonAction]
        protected void AddModelStateErrorMessages()
        {
            if (TempData["errors"] == null)
                TempData["errors"] = "";
            if (!ModelState.IsValid)
            {
                foreach (var err in ModelState.Values)
                {
                    foreach (var error in err.Errors)
                        TempData["errors"] += "<li>" + error.ErrorMessage + "</li>";
                }
            }
        }

        [NonAction]
        protected void PrepareRegisterModel(LogisticsRegisterModel model)
        {
            model.RegisterModel.AllowCustomersToSetTimeZone = false;
            model.RegisterModel.DisplayVatNumber = false;
            //form fields
            model.RegisterModel.GenderEnabled = _customerSettings.GenderEnabled;
            model.RegisterModel.DateOfBirthEnabled = _customerSettings.DateOfBirthEnabled;
            model.RegisterModel.CompanyEnabled = _customerSettings.CompanyEnabled;
            model.RegisterModel.CompanyRequired = _customerSettings.CompanyRequired;
            model.RegisterModel.StreetAddressEnabled = _customerSettings.StreetAddressEnabled;
            model.RegisterModel.StreetAddressRequired = _customerSettings.StreetAddressRequired;
            model.RegisterModel.StreetAddress2Enabled = _customerSettings.StreetAddress2Enabled;
            model.RegisterModel.StreetAddress2Required = _customerSettings.StreetAddress2Required;
            model.RegisterModel.ZipPostalCodeEnabled = _customerSettings.ZipPostalCodeEnabled;
            model.RegisterModel.ZipPostalCodeRequired = _customerSettings.ZipPostalCodeRequired;
            model.RegisterModel.CityEnabled = _customerSettings.CityEnabled;
            model.RegisterModel.CityRequired = _customerSettings.CityRequired;
            model.RegisterModel.CountryEnabled = _customerSettings.CountryEnabled;
            model.RegisterModel.StateProvinceEnabled = _customerSettings.StateProvinceEnabled;
            model.RegisterModel.PhoneEnabled = _customerSettings.PhoneEnabled;
            model.RegisterModel.PhoneRequired = _customerSettings.PhoneRequired;
            model.RegisterModel.CellPhoneEnabled = _customerSettings.CellPhoneEnabled;
            model.RegisterModel.CellPhoneRequired = _customerSettings.CellPhoneRequired;
            model.RegisterModel.FaxEnabled = _customerSettings.FaxEnabled;
            model.RegisterModel.FaxRequired = _customerSettings.FaxRequired;
            model.RegisterModel.NewsletterEnabled = _customerSettings.NewsletterEnabled;
            model.RegisterModel.UsernamesEnabled = false;
            model.RegisterModel.CheckUsernameAvailabilityEnabled = false;
            model.RegisterModel.DisplayCaptcha = _captchaSettings.Enabled && _captchaSettings.ShowOnRegistrationPage;
            model.RegisterModel.ShowBuyMembership = !_customerSettings.EnableFreeMembership;

            if (_customerSettings.CountryEnabled)
            {
                //country
                model.RegisterModel.CountryId = AddressHelper.GetDefaultCountryId();
                model.BillingAddress.CountryId = AddressHelper.GetDefaultCountryId();

                if (_customerSettings.StateProvinceEnabled)
                {
                    //states
                    var states = _stateProvinceService.GetStateProvincesByCountryId(model.RegisterModel.CountryId).ToList();
                    if (states.Count > 0)
                    {
                        foreach (var s in states)
                        {
                            model.RegisterModel.AvailableStates.Add(new SelectListItem() { Text = s.GetLocalized(x => x.Name), Value = s.Id.ToString(), Selected = (s.Id == model.RegisterModel.StateProvinceId) });
                            model.BillingAddress.AvailableStates.Add(new SelectListItem() { Text = s.GetLocalized(x => x.Name), Value = s.Id.ToString(), Selected = (s.Id == model.BillingAddress.StateProvinceId) });
                        }
                        model.RegisterModel.AvailableStates.Insert(0, new SelectListItem() { Text = "Select province", Value = "0", Selected = (model.RegisterModel.StateProvinceId == 0) });
                        model.BillingAddress.AvailableStates.Insert(0, new SelectListItem() { Text = "Select province", Value = "0", Selected = (model.RegisterModel.StateProvinceId == 0) });
                    }
                    else
                    {
                        throw new NopException("The province settings is incorrect.");
                    }

                }
            }

            //model.MembershipOptions = PrepareMembershipOptions();

            //if (!model.SelectedProductVariantId.HasValue)
            //{
            //    model.SelectedProductVariantId = model.MembershipOptions.First().ProductVariantId;
            //}
        }

        [NonAction]
        protected bool HasTrackingPackages(Customer customer)
        {
            var pkgs = _logisticsService.SearchTrackingPackages(
                customer.Id,
                null,
                null,
                null,
                0,
                1,
                _logisticsInformationSettings.TrackingIncludeDelivered); // Just peek the first one;
            return pkgs.TotalCount > 0;
        }

        [NonAction]
        protected CustomerNavigationModel GetCustomerNavigationModel(Customer customer)
        {
            var model = new CustomerNavigationModel();

            model.HideAvatar = !_customerSettings.AllowCustomersToUploadAvatars;
            model.HideRewardPoints = !_rewardPointsSettings.Enabled;
            model.HideForumSubscriptions = !_forumSettings.ForumsEnabled || !_forumSettings.AllowCustomersToManageSubscriptions;
            model.HideReturnRequests = !_orderSettings.ReturnRequestsEnabled || _orderService.SearchReturnRequests(customer.Id, 0, null, 0, 1).Count == 0;
            model.HideDownloadableProducts = _customerSettings.HideDownloadableProductsTab;
            model.HideBackInStockSubscriptions = _customerSettings.HideBackInStockSubscriptionsTab;
            model.HideTracking = !_customerSettings.AlwaysShowTrackingTab;
            model.HideInvoices = !_customerSettings.AlwaysShowInvoiceTab && _invoiceService.GetInvoicesByCustomerId(customer.Id).Count < 1;
            model.HidePasswordRecovery = true;
            if (!customer.IsRegistered())
            {
                model.HideInfo = true;
                model.HideOrders = true;
                model.HideAddresses = true;
                model.HideChangePassword = true;
                model.HideMembership = true;
                model.HideInvoices = true;
                model.HideShipments = true;
                model.HideReturnRequests = true;
                model.HideSettings = true;
            }

            return model;
        }

        [NonAction]
        private int GetExpireDaysByProduct(int productVariantId)
        {
            //TODO: Remove to logistics service
            return _logisticsInformationSettings.LoadMembershipOptions()
                .Where(o => o.ProductVariantId == productVariantId)
                .First()
                .Value;
        }

        [NonAction]
        private bool ValidateRegister()
        {
            //validation
            var cart = _workContext.CurrentCustomer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.Logistics).ToList();
            if (cart.Count != 1)
            {
                return false;
            }

            return _workContext.CurrentCustomer.IsGuest();
        }

        [NonAction]
        private void PromoteCustomer(Customer customer)
        {
            var cr = _customerService.GetAllCustomerRoles(true)
                .Where(r => r.SystemName == SystemCustomerRoleNames.LogisticsMember)
                .Single();
            customer.CustomerRoleMappings.Add(new CustomerRoleMapping() { CustomerId = customer.Id, CustomerRoleId = cr.Id, StartDate = DateTime.UtcNow });
            _customerService.UpdateCustomer(customer);

            //_authenticationService.SignIn(customer, true);

            //notifications
            if (_customerSettings.NotifyNewCustomerRegistration)
                _workflowMessageService.SendCustomerRegisteredNotificationMessage(customer, _localizationSettings.DefaultAdminLanguageId);

            //send customer welcome message
            _workflowMessageService.SendCustomerWelcomeMessage(customer, _workContext.WorkingLanguage.Id);
        }

        private void ExtendMembership(Customer customer)
        {
            var productVariantId = customer.ShoppingCartItems
                .Where(sci => sci.ShoppingCartType == ShoppingCartType.Logistics)
                .Single().ProductVariantId;
            int days = GetExpireDaysByProduct(productVariantId);
            var expireDate = customer.GetAttribute<DateTime?>(SystemCustomerAttributeNames.LogisticsMemberExpireDateTimeOnUtc, _genericAttributeService);

            if (!expireDate.HasValue)
            {
                expireDate = DateTime.UtcNow;
            }

            if (!_logisticsInformationSettings.MembershipInHour)
            {
                expireDate = new DateTime(expireDate.Value.Year, expireDate.Value.Month, expireDate.Value.Day).AddDays(days);
            }
            else
            {
                expireDate = expireDate.Value.AddDays(days);
            }

            if (expireDate < DateTime.UtcNow)
            {
                expireDate = DateTime.UtcNow;
            }

            _genericAttributeService.SaveAttribute<DateTime?>(customer, SystemCustomerAttributeNames.LogisticsMemberExpireDateTimeOnUtc, expireDate);
        }

        [NonAction]
        private void AddMembershipToCart(int productVariantId)
        {
            var productVariant = _productService.GetProductVariantById(productVariantId);
            if (productVariant == null)
                throw new NopException("Membership product variant (ID:{0}) doesn't exsit.", productVariantId);

            ClearShoppingCart();

            var addToCartWarnings = new List<string>();
            addToCartWarnings.AddRange(_shoppingCartService.AddToCart(
                _workContext.CurrentCustomer,
                productVariant, ShoppingCartType.Logistics, null, 0m, 1, false));
            if (addToCartWarnings.Count > 0)
            {
                throw new NopException("Add to Logistics cart with warnings: {0}", addToCartWarnings.First());
            }
        }

        public string RenderMessages(List<string> notices = null, List<string> warnings = null)
        {
            var messages = "";
            if (notices != null && notices.Count > 0)
            {
                messages += "<div class='alert alert-success alert-dismissible' role='alert'><button type='button' class='close' data-dismiss='alert' aria-label='Close'><span aria-hidden='true'>&times;</span></button><ul class='notices'>";
                foreach (var n in notices)
                {
                    messages += "<li>" + n + "</li>";
                }
                messages += "</ul></div>";
            }
            if (warnings != null && warnings.Count > 0)
            {
                messages += "<div class='alert alert-warning alert-dismissible' role='alert'><button type='button' class='close' data-dismiss='alert' aria-label='Close'><span aria-hidden='true'>&times;</span></button><ul class='notices'>";
                foreach (var w in warnings)
                {
                    messages += "<li>" + w + "</li>";
                }
                messages += "</ul></div>";
            }
            if (!ModelState.IsValid)
            {
                messages += "<div class='alert alert-danger alert-dismissible' role='alert'><button type='button' class='close' data-dismiss='alert' aria-label='Close'><span aria-hidden='true'>&times;</span></button><ul class='errors'>";
                var errorlist = ModelState.Select(x => x.Value.Errors)
                    .Where(y => y.Count > 0)
                    .ToList();
                foreach (var err in errorlist)
                {
                    foreach (var e in err)
                    {
                        messages += "<li>" + e.ErrorMessage + "</li>";
                    }
                }
                messages += "</ul></div>";
            }
            return messages;
        }

        private void PlaceOrder(Customer customer)
        {
            var productVariant = customer
                .ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.Logistics)
                .Single()
                .ProductVariant;

            #region Create Order

            var subTotal = productVariant.Price;
            var tax = subTotal * _logisticsInformationSettings.TaxRate;
            var total = subTotal + tax;
            total = subTotal + tax;

            int languageId = _workContext.WorkingLanguage.Id;

            //TODO: Too much hard coded here
            var order = new Order()
            {
                OrderGuid = Guid.NewGuid(),
                CustomerId = customer.Id,
                CustomerLanguageId = languageId,
                CustomerTaxDisplayType = Nop.Core.Domain.Tax.TaxDisplayType.IncludingTax,
                CustomerIp = _webHelper.GetCurrentIpAddress(),
                OrderSubtotalInclTax = total,
                OrderSubtotalExclTax = subTotal,
                OrderSubTotalDiscountInclTax = decimal.Zero,
                OrderSubTotalDiscountExclTax = decimal.Zero,
                OrderShippingInclTax = decimal.Zero,
                OrderShippingExclTax = decimal.Zero,
                PaymentMethodAdditionalFeeInclTax = decimal.Zero,
                PaymentMethodAdditionalFeeExclTax = decimal.Zero,
                TaxRates = _logisticsInformationSettings.TaxRate.ToString(),
                OrderTax = tax,
                OrderTotal = total,
                RefundedAmount = decimal.Zero,
                OrderDiscount = decimal.Zero,
                CheckoutAttributeDescription = string.Empty,
                CheckoutAttributesXml = string.Empty,
                CustomerCurrencyCode = "CAD",
                CurrencyRate = 1M,
                AffiliateId = null,
                OrderStatus = OrderStatus.Complete,
                AllowStoringCreditCardNumber = false,
                CardType = string.Empty,
                CardName = string.Empty,
                CardNumber = string.Empty,
                MaskedCreditCardNumber = string.Empty,
                CardCvv2 = string.Empty,
                CardExpirationMonth = string.Empty,
                CardExpirationYear = string.Empty,
                PaymentMethodSystemName = string.Empty,
                AuthorizationTransactionId = string.Empty,
                AuthorizationTransactionCode = string.Empty,
                AuthorizationTransactionResult = string.Empty,
                CaptureTransactionId = string.Empty,
                CaptureTransactionResult = string.Empty,
                SubscriptionTransactionId = string.Empty,
                PurchaseOrderNumber = string.Empty,
                PaymentStatus = Nop.Core.Domain.Payments.PaymentStatus.Paid,
                PaidDateUtc = DateTime.UtcNow,
                BillingAddress = customer.BillingAddress,
                ShippingAddress = customer.ShippingAddress,
                ShippingStatus = Nop.Core.Domain.Shipping.ShippingStatus.ShippingNotRequired,
                ShippingMethod = "N/A",
                ShippingRateComputationMethodSystemName = string.Empty,
                VatNumber = string.Empty,
                CreatedOnUtc = DateTime.UtcNow,
                OrderKind = OrderKind.ExpressMembership
            };
            _orderService.InsertOrder(order);



            #endregion

            #region Add Product Variant

            var opv = new OrderProductVariant()
            {
                OrderProductVariantGuid = Guid.NewGuid(),
                Order = order,
                ProductVariantId = customer.ShoppingCartItems
                    .Where(sci => sci.ShoppingCartType == ShoppingCartType.Logistics)
                    .Single()
                    .ProductVariantId,
                UnitPriceInclTax = total,
                UnitPriceExclTax = subTotal,
                PriceInclTax = total,
                PriceExclTax = subTotal,
                AttributeDescription = string.Empty,
                AttributesXml = string.Empty,
                Quantity = 1,
                DiscountAmountInclTax = decimal.Zero,
                DiscountAmountExclTax = decimal.Zero,
                DownloadCount = 0,
                IsDownloadActivated = false,
                LicenseDownloadId = 0,
                ItemWeight = null
            };

            order.OrderProductVariants.Add(opv);
            _orderService.UpdateOrder(order);

            #endregion

            //notes, messages
            order.OrderNotes.Add(new OrderNote()
            {
                Note = "Membership extended placed",
                DisplayToCustomer = false,
                CreatedOnUtc = DateTime.UtcNow
            });
            _orderService.UpdateOrder(order);

            int orderPlacedCustomerNotificationQueuedEmailId = _workflowMessageService.SendLogisticsMembershipNotification(order, order.CustomerLanguageId);
            if (orderPlacedCustomerNotificationQueuedEmailId > 0)
            {
                order.OrderNotes.Add(new OrderNote()
                {
                    Note = string.Format("\"Logistics Membership Extended\" email (to customer) has been queued. Queued email identifier: {0}.", orderPlacedCustomerNotificationQueuedEmailId),
                    DisplayToCustomer = false,
                    CreatedOnUtc = DateTime.UtcNow
                });
                _orderService.UpdateOrder(order);
            }

            _customerActivityService.InsertActivity("SpotsExpress", "Extended membership.", customer, order.Id);
        }

        private void ClearShoppingCart()
        {
            _workContext.CurrentCustomer.ShoppingCartItems
                .Where(sci => sci.ShoppingCartType == ShoppingCartType.Logistics)
                .ToList()
                .ForEach(sci => _shoppingCartService.DeleteShoppingCartItem(sci));
        }

        [NonAction]
        protected void PrepareCustomerInfoModel(CustomerInfoModel model, Customer customer, bool excludeProperties)
        {
            if (model == null)
                throw new ArgumentNullException("model");

            if (customer == null)
                throw new ArgumentNullException("customer");

            model.AllowCustomersToSetTimeZone = _dateTimeSettings.AllowCustomersToSetTimeZone;
            foreach (var tzi in _dateTimeHelper.GetSystemTimeZones())
                model.AvailableTimeZones.Add(new SelectListItem() { Text = tzi.DisplayName, Value = tzi.Id, Selected = (excludeProperties ? tzi.Id == model.TimeZoneId : tzi.Id == _dateTimeHelper.CurrentTimeZone.Id) });

            model.AvatarUrl = _pictureService.GetPictureUrl(
                customer.GetAttribute<int>(SystemCustomerAttributeNames.AvatarPictureId),
                _mediaSettings.AvatarPictureSize,
                false);

            if (!excludeProperties)
            {
                model.VatNumber = customer.VatNumber;
                model.FirstName = customer.GetAttribute<string>(SystemCustomerAttributeNames.FirstName);
                model.LastName = customer.GetAttribute<string>(SystemCustomerAttributeNames.LastName);
                model.Gender = customer.GetAttribute<string>(SystemCustomerAttributeNames.Gender);
                var dateOfBirth = customer.GetAttribute<DateTime?>(SystemCustomerAttributeNames.DateOfBirth);
                if (dateOfBirth.HasValue)
                {
                    model.DateOfBirthDay = dateOfBirth.Value.Day;
                    model.DateOfBirthMonth = dateOfBirth.Value.Month;
                    model.DateOfBirthYear = dateOfBirth.Value.Year;
                }
                model.Company = customer.GetAttribute<string>(SystemCustomerAttributeNames.Company);
                model.StreetAddress = customer.GetAttribute<string>(SystemCustomerAttributeNames.StreetAddress);
                model.StreetAddress2 = customer.GetAttribute<string>(SystemCustomerAttributeNames.StreetAddress2);
                model.ZipPostalCode = customer.GetAttribute<string>(SystemCustomerAttributeNames.ZipPostalCode);
                model.City = customer.GetAttribute<string>(SystemCustomerAttributeNames.City);
                model.CountryId = customer.GetAttribute<int>(SystemCustomerAttributeNames.CountryId);
                model.StateProvinceId = customer.GetAttribute<int>(SystemCustomerAttributeNames.StateProvinceId);
                model.Phone = customer.GetAttribute<string>(SystemCustomerAttributeNames.Phone);
                model.CellPhone = customer.GetAttribute<string>(SystemCustomerAttributeNames.CellPhone);
                model.Fax = customer.GetAttribute<string>(SystemCustomerAttributeNames.Fax);

                //newsletter
                var newsletter = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmail(customer.Email);
                model.Newsletter = newsletter != null && newsletter.Active;

                model.Signature = customer.GetAttribute<string>(SystemCustomerAttributeNames.Signature);

                model.Email = customer.Email;
                model.Username = customer.Username;
            }
            else
            {
                if (_customerSettings.UsernamesEnabled && !_customerSettings.AllowUsersToChangeUsernames)
                    model.Username = customer.Username;
            }

            //countries and states
            if (_customerSettings.CountryEnabled)
            {
                model.AvailableCountries.Add(new SelectListItem() { Text = _localizationService.GetResource("Address.SelectCountry"), Value = "0" });
                foreach (var c in _countryService.GetAllCountries())
                {
                    model.AvailableCountries.Add(new SelectListItem()
                    {
                        Text = c.GetLocalized(x => x.Name),
                        Value = c.Id.ToString(),
                        Selected = c.Id == model.CountryId
                    });
                }

                if (_customerSettings.StateProvinceEnabled)
                {
                    //states
                    var states = _stateProvinceService.GetStateProvincesByCountryId(model.CountryId).ToList();
                    if (states.Count > 0)
                    {
                        foreach (var s in states)
                            model.AvailableStates.Add(new SelectListItem() { Text = s.GetLocalized(x => x.Name), Value = s.Id.ToString(), Selected = (s.Id == model.StateProvinceId) });
                    }
                    else
                        model.AvailableStates.Add(new SelectListItem() { Text = _localizationService.GetResource("Address.OtherNonUS"), Value = "0" });

                }
            }
            DateTime monthlyDate = _dateTimeHelper.ConvertToUserTime(DateTime.UtcNow.AddDays(-30), DateTimeKind.Utc);
            DateTime YTDDate = _dateTimeHelper.ConvertToUserTime(new DateTime(DateTime.Now.Year, 1, 1), DateTimeKind.Utc);
            var invoices = _invoiceService.GetInvoicesByCustomerId(customer.Id);
            var pkgs = _logisticsService.SearchTrackingPackages(
                customer.Id, monthlyDate, null, "", 0, 10000, _logisticsInformationSettings.TrackingIncludeDelivered);

            model.DisplayVatNumber = _taxSettings.EuVatEnabled;
            model.VatNumberStatusNote = customer.VatNumberStatus.GetLocalizedEnum(_localizationService, _workContext);
            model.GenderEnabled = _customerSettings.GenderEnabled;
            model.DateOfBirthEnabled = _customerSettings.DateOfBirthEnabled;
            model.CompanyEnabled = _customerSettings.CompanyEnabled;
            model.CompanyRequired = _customerSettings.CompanyRequired;
            model.StreetAddressEnabled = _customerSettings.StreetAddressEnabled;
            model.StreetAddressRequired = _customerSettings.StreetAddressRequired;
            model.StreetAddress2Enabled = _customerSettings.StreetAddress2Enabled;
            model.StreetAddress2Required = _customerSettings.StreetAddress2Required;
            model.ZipPostalCodeEnabled = _customerSettings.ZipPostalCodeEnabled;
            model.ZipPostalCodeRequired = _customerSettings.ZipPostalCodeRequired;
            model.CityEnabled = _customerSettings.CityEnabled;
            model.CityRequired = _customerSettings.CityRequired;
            model.CountryEnabled = _customerSettings.CountryEnabled;
            model.StateProvinceEnabled = _customerSettings.StateProvinceEnabled;
            model.PhoneEnabled = _customerSettings.PhoneEnabled;
            model.PhoneRequired = _customerSettings.PhoneRequired;
            model.FaxEnabled = _customerSettings.FaxEnabled;
            model.FaxRequired = _customerSettings.FaxRequired;
            model.NewsletterEnabled = _customerSettings.NewsletterEnabled;
            model.UsernamesEnabled = _customerSettings.UsernamesEnabled;
            model.AllowUsersToChangeUsernames = _customerSettings.AllowUsersToChangeUsernames;
            model.CheckUsernameAvailabilityEnabled = _customerSettings.CheckUsernameAvailabilityEnabled;
            model.SignatureEnabled = _forumSettings.ForumsEnabled && _forumSettings.SignaturesEnabled;
            model.HasPendingOrder = _logisticsOrderProcessingService.HasPendingOrders(customer);
            model.OrderCount = customer.Orders.Count;
            model.OrderMonthlyCount = customer.Orders.Where(o => o.OrderKind == OrderKind.Commerce && _dateTimeHelper.ConvertToUserTime(o.CreatedOnUtc, DateTimeKind.Utc) >= monthlyDate && !o.Deleted).Count();
            model.OrderReturnCount = customer.ReturnRequests.Count;
            model.OrderReturnMonthlyCount = customer.ReturnRequests.Where(o => _dateTimeHelper.ConvertToUserTime(o.CreatedOnUtc, DateTimeKind.Utc) >= monthlyDate).Count();
            model.InvoiceCount = invoices.Count;
            model.InvoiceYTDCount = invoices.Where(i => _dateTimeHelper.ConvertToUserTime(i.CreatedOnUtc, DateTimeKind.Utc) >= YTDDate).Count();
            model.ShipmentCount = pkgs.TotalCount;
            model.ShipmentMonthlyCount = pkgs.Where(p => _dateTimeHelper.ConvertToUserTime(p.CreatedOnUtc, DateTimeKind.Utc) >= monthlyDate).Count();
            model.AddressCount = customer.Addresses.Count;
            model.CreatedDate = customer.CreatedOnUtc;
            model.TimeZoneId = customer.TimeZoneId;

            // Membership and Region
            model.CurrentMembershipName = "Regular Member";
            var memberships = _customerService.GetAllClubMemberships().Where(m => m.ProductVariantId.HasValue && m.ProductVariantId.Value > 0).ToList();
            var currentRole = customer.CustomerRoleMappings.FirstOrDefault(crm => (!crm.EndDate.HasValue || crm.EndDate > DateTime.UtcNow)
                    && crm.CustomerRole.SystemName == SystemCustomerRoleNames.DreamFactoryUser);
            if (currentRole != null)
            {
                model.CurrentMembershipName = "SpotsHUB Club Member";
                if (currentRole.EndDate.HasValue)
                {
                    model.MembershipExpiringDate = currentRole.EndDate.Value;
                }
                else
                    model.MembershipExpiringDate = DateTime.UtcNow.AddDays(-1);
            }

            model.CurrentRegionName = "No Region";
            var regions = _regionService.GetAllRegions();
            if (customer.Region != null)
            {
                var region = regions.FirstOrDefault(r => r.Id == customer.Region.Id);
                if (region != null)
                    model.CurrentRegionName = region.Name;
            }

            // Orders

            var orders = _orderService.GetOrdersByCustomerId(customer.Id, 1, OrderKind.Commerce, 0, 10).Where(x => _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc) > monthlyDate);
            var packages = _logisticsService.SearchTrackingPackages(
                    customer.Id,
                    monthlyDate,
                    null,
                    "",
                    0,
                    10,
                    _logisticsInformationSettings.TrackingIncludeDelivered);
            //LOAD EVENT SETTING 
            int eventLimitCount = _settingService.GetSettingByKey<int>("display.limitMessage", 10);
            foreach (var order in orders)
            {
                var time = "";
                if (order.CreatedOnUtc < DateTime.UtcNow.AddDays(-7))
                {
                    time = _dateTimeHelper.ConvertToUserTime(order.CreatedOnUtc, DateTimeKind.Utc).ToString();
                }
                else
                {
                    var timedif = DateTime.UtcNow - order.CreatedOnUtc;
                    if (timedif.Days >= 1)
                    {
                        if (timedif.Days == 1)
                        {
                            time = timedif.Days.ToString() + " day ago";
                        }
                        else
                        {
                            time = timedif.Days.ToString() + " days ago";
                        }
                    }
                    else if (timedif.Hours >= 1)
                    {
                        if (timedif.Hours == 1)
                        {
                            time = timedif.Hours.ToString() + " hour ago";
                        }
                        else
                        {
                            time = timedif.Hours.ToString() + " hours ago";
                        }
                    }
                    else if (timedif.Minutes >= 1)
                    {
                        if (timedif.Minutes == 1)
                        {
                            time = timedif.Minutes.ToString() + " minute ago";
                        }
                        else
                        {
                            time = timedif.Minutes.ToString() + " minutess ago";
                        }
                    }
                    else
                    {
                        time = timedif.Seconds.ToString() + " seconds ago";
                    }
                }
                model.Events.Add(new CustomerInfoModel.CustomerEvent
                {
                    Time = order.CreatedOnUtc,
                    TimeString = time,
                    EventName = "Order #" + order.Id + " was created."
                });
            }

            foreach (var package in packages)
            {
                var time = "";
                if (package.CreatedOnUtc < DateTime.UtcNow.AddDays(-7))
                {
                    time = _dateTimeHelper.ConvertToUserTime(package.CreatedOnUtc, DateTimeKind.Utc).ToString();
                }
                else
                {
                    var timedif = DateTime.UtcNow - package.CreatedOnUtc;
                    if (timedif.Days >= 1)
                    {
                        if (timedif.Days == 1)
                        {
                            time = timedif.Days.ToString() + " day ago";
                        }
                        else
                        {
                            time = timedif.Days.ToString() + " days ago";
                        }
                    }
                    else if (timedif.Hours >= 1)
                    {
                        if (timedif.Hours == 1)
                        {
                            time = timedif.Hours.ToString() + " hour ago";
                        }
                        else
                        {
                            time = timedif.Hours.ToString() + " hours ago";
                        }
                    }
                    else if (timedif.Minutes >= 1)
                    {
                        if (timedif.Minutes == 1)
                        {
                            time = timedif.Minutes.ToString() + " minute ago";
                        }
                        else
                        {
                            time = timedif.Minutes.ToString() + " minutess ago";
                        }
                    }
                    else
                    {
                        time = timedif.Seconds.ToString() + " seconds ago";
                    }
                }
                model.Events.Add(new CustomerInfoModel.CustomerEvent
                {
                    Time = package.CreatedOnUtc,
                    TimeString = time,
                    EventName = "Package tracking id #" + package.Shipment.TrackingNumber + " was created."
                });
                if (package.UpdatedOnUtc != null && package.CreatedOnUtc < package.UpdatedOnUtc.Value)
                {
                    if (package.UpdatedOnUtc < DateTime.UtcNow.AddDays(-7))
                    {
                        time = _dateTimeHelper.ConvertToUserTime(package.UpdatedOnUtc.Value, DateTimeKind.Utc).ToString();
                    }
                    else
                    {
                        var timedif = DateTime.UtcNow - package.UpdatedOnUtc.Value;
                        if (timedif.Days >= 1)
                        {
                            if (timedif.Days == 1)
                            {
                                time = timedif.Days.ToString() + " day ago";
                            }
                            else
                            {
                                time = timedif.Days.ToString() + " days ago";
                            }
                        }
                        else if (timedif.Hours >= 1)
                        {
                            if (timedif.Hours == 1)
                            {
                                time = timedif.Hours.ToString() + " hour ago";
                            }
                            else
                            {
                                time = timedif.Hours.ToString() + " hours ago";
                            }
                        }
                        else if (timedif.Minutes >= 1)
                        {
                            if (timedif.Minutes == 1)
                            {
                                time = timedif.Minutes.ToString() + " minute ago";
                            }
                            else
                            {
                                time = timedif.Minutes.ToString() + " minutess ago";
                            }
                        }
                        else
                        {
                            time = timedif.Seconds.ToString() + " seconds ago";
                        }
                    }
                    if (package.Status == ShippingStatus.Delivered)
                    {
                        model.Events.Add(new CustomerInfoModel.CustomerEvent
                        {
                            Time = package.UpdatedOnUtc.Value,
                            TimeString = time,
                            EventName = "Package tracking id #" + package.Shipment.TrackingNumber + " was delivered."
                        });
                    }
                    else if (package.Status == ShippingStatus.Cancelled)
                    {
                        model.Events.Add(new CustomerInfoModel.CustomerEvent
                        {
                            Time = package.UpdatedOnUtc.Value,
                            TimeString = time,
                            EventName = "Package tracking id #" + package.Shipment.TrackingNumber + " was cancelled."
                        });
                    }
                    else
                    {
                        model.Events.Add(new CustomerInfoModel.CustomerEvent
                        {
                            Time = package.UpdatedOnUtc.Value,
                            TimeString = time,
                            EventName = "Package tracking id #" + package.Shipment.TrackingNumber + " (" + package.Status.ToString() + ") was updated."
                        });
                    }
                }
            }

            model.Events = model.Events.OrderByDescending(e => e.Time).Take(eventLimitCount).ToList();
            var accType = _logisticsOrderProcessingService.GetChargeRule(customer);
            switch (accType)
            {
                case ChargeRule.Membership:
                    model.AccountType = _localizationService.GetResource("Logistics.AccountType.Membership");
                    break;
                case ChargeRule.Volume:
                    model.AccountType = _localizationService.GetResource("Logistics.AccountType.Volume");
                    break;
                case ChargeRule.PayPerUse:
                default:
                    //model.AccountType = _localizationService.GetResource("Logistics.AccountType.PayPerUse");
                    model.AccountType = "";
                    break;
            }

            if (accType == ChargeRule.Membership || accType == ChargeRule.Volume)
            {
                switch ((InvoiceStatus)customer.GetAttribute<int>(SystemCustomerAttributeNames.PreferredPaymentMethodId))
                {
                    case InvoiceStatus.PaidByCheck:
                        model.PreferredPaymentMethod = _localizationService.GetResource("Logistics.PaymentMethod.PayByCheck");
                        break;
                    case InvoiceStatus.PaidByCreditCard:
                        model.PreferredPaymentMethod = _localizationService.GetResource("Logistics.PaymentMethod.PayByCreditCard");
                        break;
                    default:
                        break;
                }
            }

            //external authentication
            foreach (var ear in _openAuthenticationService.GetExternalIdentifiersFor(customer))
            {
                var authMethod = _openAuthenticationService.LoadExternalAuthenticationMethodBySystemName(ear.ProviderSystemName);
                if (authMethod == null || !authMethod.IsMethodActive(_externalAuthenticationSettings))
                    continue;

                model.AssociatedExternalAuthRecords.Add(new CustomerInfoModel.AssociatedExternalAuthModel()
                {
                    Id = ear.Id,
                    Email = ear.Email,
                    ExternalIdentifier = ear.ExternalIdentifier,
                    AuthMethodName = authMethod.GetLocalizedFriendlyName(_localizationService, _workContext.WorkingLanguage.Id)
                });
            }

            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Info;
        }

        [NonAction]
        protected CustomerOrderListModel PrepareCustomerOrderListModel(Customer customer)
        {
            if (customer == null)
                throw new ArgumentNullException("customer");

            var model = new CustomerOrderListModel();
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Orders;

            var recurringPayments = _orderService.SearchRecurringPayments(customer.Id, 0, null, 0, int.MaxValue);
            foreach (var recurringPayment in recurringPayments)
            {
                var recurringPaymentModel = new CustomerOrderListModel.RecurringOrderModel()
                {
                    Id = recurringPayment.Id,
                    StartDate = _dateTimeHelper.ConvertToUserTime(recurringPayment.StartDateUtc, DateTimeKind.Utc).ToString(),
                    CycleInfo = string.Format("{0} {1}", recurringPayment.CycleLength, recurringPayment.CyclePeriod.GetLocalizedEnum(_localizationService, _workContext)),
                    NextPayment = recurringPayment.NextPaymentDate.HasValue ? _dateTimeHelper.ConvertToUserTime(recurringPayment.NextPaymentDate.Value, DateTimeKind.Utc).ToString() : "",
                    TotalCycles = recurringPayment.TotalCycles,
                    CyclesRemaining = recurringPayment.CyclesRemaining,
                    InitialOrderId = recurringPayment.InitialOrder.Id,
                    CanCancel = _orderProcessingService.CanCancelRecurringPayment(customer, recurringPayment),
                };

                model.RecurringOrders.Add(recurringPaymentModel);
            }

            return model;
        }

        [NonAction]
        protected CustomerTrackingModel PrepareTrackingModel(Customer customer)
        {
            var model = new CustomerTrackingModel();
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Tracking;

            model.StartDate = null;
            model.EndDate = null;
            model.TrackingNumber = null;
            //TODO: Put in settings and remove hard-coded strings.
            model.TrackingDays = 90;
            model.TrackingDaysOptions.Add(new SelectListItem() { Selected = false, Text = "Last 7 Days", Value = "7" });
            model.TrackingDaysOptions.Add(new SelectListItem() { Selected = true, Text = "Last 15 Days", Value = "15" });
            model.TrackingDaysOptions.Add(new SelectListItem() { Selected = true, Text = "Last 30 Days", Value = "30" });
            model.TrackingDaysOptions.Add(new SelectListItem() { Selected = false, Text = "Last 3 Months", Value = "90" });
            model.TrackingDaysOptions.Add(new SelectListItem() { Selected = false, Text = "Last 6 Months", Value = "180" });
            model.TrackingDaysOptions.Add(new SelectListItem() { Selected = false, Text = "Last 12 Months", Value = "365" });
            model.TrackingDaysOptions.Add(new SelectListItem() { Selected = false, Text = "Last 2 Years", Value = "730" });
            model.TrackingDaysOptions.Add(new SelectListItem() { Selected = false, Text = "All Time", Value = "0" });
            return model;
        }

        [NonAction]
        protected CustomerTrackingModel.TrackingPackageModel PrepareTrackingPackageModel(LogisticsPackage package)
        {
            var ct = _dateTimeHelper.ConvertToUserTime(package.CreatedOnUtc, System.DateTimeKind.Utc);
            DateTime? pt = null, dt = null, rt = null;

            if (package.Shipment.ShippedDateUtc.HasValue)
            {
                pt = _dateTimeHelper.ConvertToUserTime(package.Shipment.ShippedDateUtc.Value, DateTimeKind.Utc);
            }

            if (package.Shipment.DeliveryDateUtc.HasValue)
            {
                dt = _dateTimeHelper.ConvertToUserTime(package.Shipment.DeliveryDateUtc.Value, DateTimeKind.Utc);
            }

            if (package.ReadyOnUtc.HasValue)
            {
                rt = _dateTimeHelper.ConvertToUserTime(package.ReadyOnUtc.Value);
            }

            //Package note info by admin
            var pkgNoteByAdmin = package.PackageNotes.Where(pkn => pkn.DisplayToCustomer && pkn.TypeId == (int)PackageNoteType.AdminNote)
                                                    .OrderByDescending(pkn => pkn.CreatedOnUtc)
                                                    .Select(pkn => pkn.Note)
                                                    .FirstOrDefault();

            var baseWeight = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId);
            var baseWeightIn = baseWeight != null ? baseWeight.Name : "";
            var baseDimension = _measureService.GetMeasureDimensionById(_measureSettings.BaseDimensionId);
            var baseDimensionIn = baseDimension != null ? baseDimension.Name : "";

            StringBuilder pkgMeasure = new StringBuilder();
            if (package.Shipment.Length.HasValue && package.Shipment.Width.HasValue && package.Shipment.Height.HasValue)
            {
                pkgMeasure.AppendFormat("{1:F1} x {2:F1} x {3:F1} ({0})", baseDimensionIn, package.Shipment.Length.Value, package.Shipment.Width.Value, package.Shipment.Height.Value);

                if (package.Shipment.TotalWeight.HasValue)
                {
                    pkgMeasure.AppendFormat(" {0:F1} ({1})", package.Shipment.TotalWeight.Value, baseWeightIn);
                }
            }
            else
            {
                pkgMeasure.Append(_localizationService.GetResource("Logistics.StandardPackage"));
            }

            if (package.Shipment.Attributes.HasValue && package.Shipment.Attributes.Value != 0)
            {
                pkgMeasure.Append(" ");
                pkgMeasure.Append(((AddtionalAttributes)package.Shipment.Attributes).GetLocalizedEnum(_localizationService, _workContext.WorkingLanguage.Id));
            }

            if (package.Shipment.InsuranceValue.HasValue && package.Shipment.InsuranceValue.Value != 0)
            {
                if (pkgMeasure.Length > 0)
                    pkgMeasure.Append(" ");
                pkgMeasure.AppendFormat(_localizationService.GetResource("Logistics.Order.InsuranceFormat"), package.Shipment.InsuranceValue.Value);
            }

            var statusStr = package.Status.GetLocalizedEnum(_localizationService, _workContext);
            var cookieAuth = String.Format("spotshub.trackauth.{0}", package.ShipmentId.ToString() + package.Id.ToString());
            bool authorizedToDownload = package.ApplicatorId == _workContext.CurrentCustomer.Id || package.Shipment.Order.CustomerId == _workContext.CurrentCustomer.Id || Request.Cookies[cookieAuth] != null;
            bool shippingLabelAvailable = package.Status != ShippingStatus.Cancelled && package.Status != ShippingStatus.CancelledNotRefund && package.Status != ShippingStatus.CancelledWithRefund &&
                package.Status != ShippingStatus.Delivered && package.Status != ShippingStatus.NotYetShipped && package.Status != ShippingStatus.ShippingNotRequired;

            return new CustomerTrackingModel.TrackingPackageModel()
            {
                Id = package.Id,
                CreatedTime = ct,
                CreatedTimeStr = ct.ToNoSecondString(_workContext),
                PickupTime = pt,
                PickupTimeStr = pt.ToNoSecondString(_workContext, _localizationService),
                DeliveryTime = dt,
                DeliveryTimeStr = dt.ToNoSecondString(_workContext, _localizationService),
                Reference = package.Shipment.Comment,
                DeliveryAddress = package.DeliveryLocation.Address.FormatAddressShort(),
                PickUpAddress = package.PickUpLocation.Address.FormatAddressShort(),
                Status = (package.Status == ShippingStatus.NotYetReady && rt.HasValue) ?
                    String.Format(_localizationService.GetResource("Logistics.MyHub.Package.ReadyOnUTC"), rt.Value.ToNoSecondString(_workContext)) :
                    (pkgNoteByAdmin == null ? statusStr : String.Format(_localizationService.GetResource("Logistics.MyHub.StatusWithNote"), statusStr, pkgNoteByAdmin)),
                ShipmentId = package.ShipmentId,
                OrderId = package.Shipment.OrderId,
                TrackingNumber = package.Shipment == null ? "N/A" : package.Shipment.TrackingNumber,
                PackageMeasurement = pkgMeasure.ToString(),
                DownloadShippingLabelLink = authorizedToDownload && shippingLabelAvailable ? "<a class='btn btn-normal' target='_blank' href='" + Url.Action("DownloadWaybill", "Order", new { id = package.Id, area = "Logistics" }) + "'>" + _localizationService.GetResource("Common.Download") + "</a>" : "",
                ShipmentDetailLink = "<input type='button' class='btn btn-normal form-control shipment-tracking-details-button' value='View Details' data-id='" + package.ShipmentId + "' />",
                OrderBy = package.ApplicatorId.HasValue ? _customerService.GetCustomerById(package.ApplicatorId.Value).GetFullName() : ""
            };
        }

        [NonAction]
        protected CustomerSettingsModel PrepareCustomerSettingsModel(CustomerSettingsModel model = null)
        {
            var customer = _workContext.CurrentCustomer;
            if (model == null)
            {
                model = new CustomerSettingsModel()
                {
                    EmailPreferences = PrepareEmailPreferenceModel(customer)
                };
            }
            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.Settings;

            // Time Zone
            model.SelectedTimeZone = customer.TimeZoneId;
            if (_dateTimeSettings.AllowCustomersToSetTimeZone)
            {
                foreach (var tzi in _dateTimeHelper.GetSystemTimeZones())
                    model.AvailableTimeZones.Add(new SelectListItem() { Text = tzi.DisplayName, Value = tzi.Id, Selected = tzi.Id == model.SelectedTimeZone });
            }

            // Region
            model.SelectedRegion = customer.Region == null ? 0 : customer.Region.Id;
            model.AvailableRegions = _cacheManager.Get(ModelCacheEventConsumer.AVAILABLE_REGIONS_MODEL_KEY, () =>
            {
                var result = _regionService.GetAllRegions()
                    .Select(x => new SelectListItem()
                    {
                        Value = x.Id.ToString(),
                        Text = x.Name,
                        Selected = x.Id == model.SelectedRegion
                    })
                    .ToList();
                return result;
            });

            // Language
            model.SelectedLanguage = customer.LanguageId.HasValue ? customer.LanguageId.Value : _workContext.WorkingLanguage.Id;
            model.AvailableLanguages = _languageService.GetAllLanguages().Select(l => new SelectListItem()
                {
                    Value = l.Id.ToString(),
                    Text = l.Name,
                    Selected = l.Id == model.SelectedLanguage
                }).ToList();

            return model;
        }

        [NonAction]
        protected CustomerEmailPreferenceModel PrepareEmailPreferenceModel(Customer customer, CustomerEmailPreferenceModel model = null)
        {
            if (model == null)
                model = new CustomerEmailPreferenceModel();

            model.NavigationModel = GetCustomerNavigationModel(customer);
            model.LogisticsInvoicePaid = customer.IsMessageEnabled(MessageSettingFlags.LogisticsInvoicePaid);
            model.LogisticsInvoiceReady = customer.IsMessageEnabled(MessageSettingFlags.LogisticsInvoiceReady);
            model.LogisticsOrderPlaced = customer.IsMessageEnabled(MessageSettingFlags.LogisticsOrderPlaced);
            model.LogisticsDelivered = customer.IsMessageEnabled(MessageSettingFlags.LogisticsDelivered);
            model.LogisticsFailedPickup = customer.IsMessageEnabled(MessageSettingFlags.LogisticsFailedPickup);
            model.LogisticsSent = customer.IsMessageEnabled(MessageSettingFlags.LogisticsSent);
            //All Logistics

            model.CommerceOrderCancelled = customer.IsMessageEnabled(MessageSettingFlags.CommerceOrderCancelled);
            model.CommerceOrderCompleted = customer.IsMessageEnabled(MessageSettingFlags.CommerceOrderCompleted);
            model.CommerceOrderPlaced = customer.IsMessageEnabled(MessageSettingFlags.CommerceOrderPlaced);
            model.CommerceSent = customer.IsMessageEnabled(MessageSettingFlags.CommerceSent);
            model.CommerceDelivered = customer.IsMessageEnabled(MessageSettingFlags.CommerceDelivered);
            //AllCommerce
            model.NavigationModel.SelectedTab = CustomerNavigationEnum.EmailPreference;

            return model;
        }

        [NonAction]
        private List<MembershipTypeModel> PrepareMembershipOptions()
        {
            var productVariants = new List<Nop.Core.Domain.Catalog.ProductVariant>();

            foreach (var o in _logisticsInformationSettings.LoadMembershipOptions())
            {
                // TODO: localize
                var productVariant = _productService.GetProductVariantById(o.ProductVariantId);
                if (productVariant == null)
                    throw new NopException("Membership product variant (ID:{0}) doesn't exsit.", o.ProductVariantId);

                productVariants.Add(productVariant);
            }

            return productVariants
                .OrderBy(pv => pv.DisplayOrder)
                .Select(pv => new MembershipTypeModel() { DisplayText = pv.Description, ProductVariantId = pv.Id, Price = pv.Price })
                .ToList();
        }

        [NonAction]
        private ClubMembershipModel PrepareMembershipModel(ClubMembership membership)
        {
            if (membership == null) return null;

            return new ClubMembershipModel
            {
                Id = membership.Id,
                Description = membership.Description,
                Name = membership.Name,
                LocalShipmentFee = membership.LocalShipmentFee,
                Duration = membership.MembershipDuration,
                ProductVariantId = membership.ProductVariantId.HasValue ? membership.ProductVariantId.Value : 0
            };
        }

        [NonAction]
        private List<ClubMembershipModel> PrepareMembershipModel(IList<ClubMembership> memberships)
        {
            return memberships.Select(cms => new ClubMembershipModel
                    {
                        Id = cms.Id,
                        Name = cms.Name,
                        Description = cms.Description,
                        LocalShipmentFee = cms.LocalShipmentFee,
                        Duration = cms.MembershipDuration,
                        ProductVariantId = cms.ProductVariantId.HasValue ? cms.ProductVariantId.Value : 0
                    }).ToList();
        }

        //[NonAction]
        //private ProductModel PrepareProductModel(Product product)
        //{
        //	var productModel = new ProductModel();
        //	productModel.Id = product.Id;
        //	productModel.Name = product.Name;
        //	productModel.Description = product.FullDescription;
        //	productModel.Variants = PrepareProductVariantModel(product.ProductVariants);
        //	return productModel;

        //}


        //[NonAction]
        //private IList<SelectListItem> PrepareProductVariantModel(ICollection<ProductVariant> variants)
        //{
        //	return variants.Select(v => new SelectListItem { Value = v.Id.ToString(), Text = string.Format("{0}, {1}, Price:{2}", v.Name, v.Description, v.Price)})
        //				   .ToList();
        //}

        [NonAction]
        protected virtual string RenderAjaxNotification()
        {
            var nte = string.Format("nop.notifications.{0}", NotifyType.Error);
            var nts = string.Format("nop.notifications.{0}", NotifyType.Success);
            var nti = string.Format("nop.notifications.{0}", NotifyType.Info);

            var messages = "";
            if (TempData[nts] != null)
            {
                messages += "<div class='alert alert-success alert-dismissible' role='alert'><button type='button' class='close' data-dismiss='alert' aria-label='Close'><span aria-hidden='true'>&times;</span></button><ul>" + RenderList((List<string>)TempData[nts]) + "</ul></div>";
            }
            if (TempData[nte] != null)
            {
                messages += "<div class='alert alert-danger alert-dismissible' role='alert'><button type='button' class='close' data-dismiss='alert' aria-label='Close'><span aria-hidden='true'>&times;</span></button><ul>" + RenderList((List<string>)TempData[nte]) + "</ul></div>";
            }
            if (TempData[nti] != null)
            {
                messages += "<div class='alert alert-info alert-dismissible' role='alert'><button type='button' class='close' data-dismiss='alert' aria-label='Close'><span aria-hidden='true'>&times;</span></button><ul>" + RenderList((List<string>)TempData[nti]) + "</ul></div>";
            }

            return messages;
        }

        [NonAction]
        protected string RenderList(List<string> list)
        {
            var msg = "";
            if (list.Count > 0)
            {
                foreach (var s in list)
                {
                    msg += "<li>" + s + "</li>";
                }
            }
            return msg;
        }

        #endregion
    }
}
